waappa-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Waappa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: waappa-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Waappa API.
5
+ Author: Waappa
6
+ License: MIT
7
+ Keywords: waappa,whatsapp,waha,sdk
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # Waappa Python SDK
22
+
23
+ Official Python SDK for the Waappa API.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install waappa-sdk
29
+ ```
30
+
31
+ Requires Python 3.9 or newer.
32
+
33
+ ## Quick Start
34
+
35
+ ```python
36
+ from waappa import WaappaClient
37
+
38
+ waappa = WaappaClient(
39
+ api_key="waappa_session_api_key",
40
+ session="default",
41
+ )
42
+
43
+ waappa.send_text(
44
+ chatId="919876543210@c.us",
45
+ text="Hello from Waappa",
46
+ )
47
+ ```
48
+
49
+ The SDK sends the API key as the `Authorization` header. By default it uses:
50
+
51
+ ```text
52
+ https://api.waappa.com
53
+ ```
54
+
55
+ Use `base_url` for local or private deployments:
56
+
57
+ ```python
58
+ waappa = WaappaClient(
59
+ api_key="waappa_session_api_key",
60
+ session="default",
61
+ base_url="http://localhost:3001",
62
+ )
63
+ ```
64
+
65
+ ## Messages
66
+
67
+ ```python
68
+ waappa.send_image(
69
+ chatId="919876543210@c.us",
70
+ caption="Invoice",
71
+ file={
72
+ "mimetype": "image/jpeg",
73
+ "filename": "invoice.jpg",
74
+ "url": "https://example.com/invoice.jpg",
75
+ },
76
+ )
77
+
78
+ waappa.send_poll(
79
+ chatId="919876543210@c.us",
80
+ poll={
81
+ "name": "Choose one",
82
+ "options": ["A", "B"],
83
+ "multipleAnswers": False,
84
+ },
85
+ )
86
+ ```
87
+
88
+ Supported message helpers:
89
+
90
+ - `send_text`
91
+ - `send_image`
92
+ - `send_voice`
93
+ - `send_video`
94
+ - `send_file`
95
+ - `send_poll`
96
+ - `send_list`
97
+ - `send_contact_vcard`
98
+ - `send_location`
99
+ - `send_event`
100
+ - `edit_message`
101
+ - `delete_message`
102
+ - `get_messages`
103
+
104
+ ## Media Upload
105
+
106
+ ```python
107
+ uploaded = waappa.upload("invoice.jpg")
108
+ ```
109
+
110
+ Use the returned URL in `send_image`, `send_video`, `send_voice`, or `send_file`.
111
+
112
+ ## Groups, Contacts, Labels, LIDs, Channels
113
+
114
+ ```python
115
+ waappa.create_group("Support", ["919876543210@c.us"])
116
+
117
+ contacts = waappa.list_contacts()
118
+ labels = waappa.list_labels()
119
+ channels = waappa.list_channels()
120
+ ```
121
+
122
+ The client includes helpers for the selected Waappa API surface: groups, group participants, contacts, labels, LID/phone resolution, and channels.
123
+
124
+ ## Admin / Session Management
125
+
126
+ Session management methods require a master key:
127
+
128
+ ```python
129
+ admin = WaappaClient(api_key="mk_live_...")
130
+ sessions = admin.list_sessions()
131
+ ```
132
+
133
+ ## Errors
134
+
135
+ Failed API responses raise `WaappaError`:
136
+
137
+ ```python
138
+ from waappa import WaappaError
139
+
140
+ try:
141
+ waappa.send_text(chatId="bad", text="Hello")
142
+ except WaappaError as error:
143
+ print(error.status)
144
+ print(error.data)
145
+ ```
146
+
147
+ ## Development
148
+
149
+ ```bash
150
+ python -m compileall waappa
151
+ python -m pip wheel . --no-deps -w dist
152
+ ```
153
+
154
+ ## Publishing
155
+
156
+ ```bash
157
+ python -m build
158
+ python -m twine upload dist/*
159
+ ```
160
+
161
+ Before publishing, run a smoke test against a real Waappa API key and session.
@@ -0,0 +1,141 @@
1
+ # Waappa Python SDK
2
+
3
+ Official Python SDK for the Waappa API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install waappa-sdk
9
+ ```
10
+
11
+ Requires Python 3.9 or newer.
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from waappa import WaappaClient
17
+
18
+ waappa = WaappaClient(
19
+ api_key="waappa_session_api_key",
20
+ session="default",
21
+ )
22
+
23
+ waappa.send_text(
24
+ chatId="919876543210@c.us",
25
+ text="Hello from Waappa",
26
+ )
27
+ ```
28
+
29
+ The SDK sends the API key as the `Authorization` header. By default it uses:
30
+
31
+ ```text
32
+ https://api.waappa.com
33
+ ```
34
+
35
+ Use `base_url` for local or private deployments:
36
+
37
+ ```python
38
+ waappa = WaappaClient(
39
+ api_key="waappa_session_api_key",
40
+ session="default",
41
+ base_url="http://localhost:3001",
42
+ )
43
+ ```
44
+
45
+ ## Messages
46
+
47
+ ```python
48
+ waappa.send_image(
49
+ chatId="919876543210@c.us",
50
+ caption="Invoice",
51
+ file={
52
+ "mimetype": "image/jpeg",
53
+ "filename": "invoice.jpg",
54
+ "url": "https://example.com/invoice.jpg",
55
+ },
56
+ )
57
+
58
+ waappa.send_poll(
59
+ chatId="919876543210@c.us",
60
+ poll={
61
+ "name": "Choose one",
62
+ "options": ["A", "B"],
63
+ "multipleAnswers": False,
64
+ },
65
+ )
66
+ ```
67
+
68
+ Supported message helpers:
69
+
70
+ - `send_text`
71
+ - `send_image`
72
+ - `send_voice`
73
+ - `send_video`
74
+ - `send_file`
75
+ - `send_poll`
76
+ - `send_list`
77
+ - `send_contact_vcard`
78
+ - `send_location`
79
+ - `send_event`
80
+ - `edit_message`
81
+ - `delete_message`
82
+ - `get_messages`
83
+
84
+ ## Media Upload
85
+
86
+ ```python
87
+ uploaded = waappa.upload("invoice.jpg")
88
+ ```
89
+
90
+ Use the returned URL in `send_image`, `send_video`, `send_voice`, or `send_file`.
91
+
92
+ ## Groups, Contacts, Labels, LIDs, Channels
93
+
94
+ ```python
95
+ waappa.create_group("Support", ["919876543210@c.us"])
96
+
97
+ contacts = waappa.list_contacts()
98
+ labels = waappa.list_labels()
99
+ channels = waappa.list_channels()
100
+ ```
101
+
102
+ The client includes helpers for the selected Waappa API surface: groups, group participants, contacts, labels, LID/phone resolution, and channels.
103
+
104
+ ## Admin / Session Management
105
+
106
+ Session management methods require a master key:
107
+
108
+ ```python
109
+ admin = WaappaClient(api_key="mk_live_...")
110
+ sessions = admin.list_sessions()
111
+ ```
112
+
113
+ ## Errors
114
+
115
+ Failed API responses raise `WaappaError`:
116
+
117
+ ```python
118
+ from waappa import WaappaError
119
+
120
+ try:
121
+ waappa.send_text(chatId="bad", text="Hello")
122
+ except WaappaError as error:
123
+ print(error.status)
124
+ print(error.data)
125
+ ```
126
+
127
+ ## Development
128
+
129
+ ```bash
130
+ python -m compileall waappa
131
+ python -m pip wheel . --no-deps -w dist
132
+ ```
133
+
134
+ ## Publishing
135
+
136
+ ```bash
137
+ python -m build
138
+ python -m twine upload dist/*
139
+ ```
140
+
141
+ Before publishing, run a smoke test against a real Waappa API key and session.
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,36 @@
1
+ [metadata]
2
+ name = waappa-sdk
3
+ version = 0.1.0
4
+ description = Official Python SDK for the Waappa API.
5
+ long_description = file: README.md
6
+ long_description_content_type = text/markdown
7
+ author = Waappa
8
+ license = MIT
9
+ license_files = LICENSE
10
+ keywords = waappa, whatsapp, waha, sdk
11
+ classifiers =
12
+ Development Status :: 3 - Alpha
13
+ Intended Audience :: Developers
14
+ License :: OSI Approved :: MIT License
15
+ Programming Language :: Python :: 3
16
+ Programming Language :: Python :: 3.9
17
+ Programming Language :: Python :: 3.10
18
+ Programming Language :: Python :: 3.11
19
+ Programming Language :: Python :: 3.12
20
+
21
+ [options]
22
+ packages = find:
23
+ python_requires = >=3.9
24
+ include_package_data = True
25
+
26
+ [options.packages.find]
27
+ where = .
28
+ include = waappa*
29
+
30
+ [options.package_data]
31
+ waappa = py.typed
32
+
33
+ [egg_info]
34
+ tag_build =
35
+ tag_date = 0
36
+
@@ -0,0 +1,3 @@
1
+ from .client import WaappaClient, WaappaError
2
+
3
+ __all__ = ["WaappaClient", "WaappaError"]
@@ -0,0 +1,247 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import mimetypes
5
+ import os
6
+ import uuid
7
+ from pathlib import Path
8
+ from typing import Any, BinaryIO, Mapping
9
+ from urllib.parse import urlencode, quote
10
+ from urllib.request import Request, urlopen
11
+ from urllib.error import HTTPError
12
+
13
+
14
+ class WaappaError(Exception):
15
+ def __init__(self, status: int, data: Any):
16
+ super().__init__(f"Waappa API request failed with status {status}")
17
+ self.status = status
18
+ self.data = data
19
+
20
+
21
+ class WaappaClient:
22
+ def __init__(
23
+ self,
24
+ api_key: str,
25
+ *,
26
+ base_url: str = "https://api.waappa.com",
27
+ session: str | None = None,
28
+ timeout: float = 30.0,
29
+ ) -> None:
30
+ if not api_key:
31
+ raise ValueError("WaappaClient requires an api_key.")
32
+ self.api_key = api_key
33
+ self.base_url = base_url.rstrip("/")
34
+ self.session = session
35
+ self.timeout = timeout
36
+
37
+ def request(
38
+ self,
39
+ method: str,
40
+ path: str,
41
+ *,
42
+ query: Mapping[str, Any] | None = None,
43
+ body: Any = None,
44
+ headers: Mapping[str, str] | None = None,
45
+ ) -> Any:
46
+ url = f"{self.base_url}{path}"
47
+ clean_query = {k: v for k, v in (query or {}).items() if v is not None}
48
+ if clean_query:
49
+ url = f"{url}?{urlencode(clean_query)}"
50
+
51
+ request_headers = {"Authorization": self.api_key, **(headers or {})}
52
+ data = None
53
+ if body is not None:
54
+ if isinstance(body, bytes):
55
+ data = body
56
+ else:
57
+ request_headers.setdefault("Content-Type", "application/json")
58
+ data = json.dumps(body).encode("utf-8")
59
+
60
+ req = Request(url, data=data, headers=request_headers, method=method.upper())
61
+ try:
62
+ with urlopen(req, timeout=self.timeout) as response:
63
+ return _decode_response(response.read(), response.headers.get("Content-Type", ""))
64
+ except HTTPError as exc:
65
+ raise WaappaError(exc.code, _decode_response(exc.read(), exc.headers.get("Content-Type", ""))) from exc
66
+
67
+ def health(self) -> Any:
68
+ return self.request("GET", "/health")
69
+
70
+ def upload(self, file: str | os.PathLike[str] | BinaryIO, *, filename: str | None = None, mimetype: str | None = None) -> Any:
71
+ file_name, file_bytes = _read_upload_file(file, filename)
72
+ content_type = mimetype or mimetypes.guess_type(file_name)[0] or "application/octet-stream"
73
+ boundary = f"waappa-{uuid.uuid4().hex}"
74
+ body = _multipart_body(boundary, "file", file_name, content_type, file_bytes)
75
+ return self.request(
76
+ "POST",
77
+ "/api/upload",
78
+ body=body,
79
+ headers={"Content-Type": f"multipart/form-data; boundary={boundary}"},
80
+ )
81
+
82
+ def send_text(self, **body: Any) -> Any:
83
+ return self.request("POST", "/api/sendText", body=body)
84
+
85
+ def send_poll(self, **body: Any) -> Any:
86
+ return self.request("POST", "/api/sendPoll", body=body)
87
+
88
+ def send_list(self, **body: Any) -> Any:
89
+ return self.request("POST", "/api/sendList", body=body)
90
+
91
+ def send_contact_vcard(self, **body: Any) -> Any:
92
+ return self.request("POST", "/api/sendContactVcard", body=body)
93
+
94
+ def send_location(self, **body: Any) -> Any:
95
+ return self.request("POST", "/api/sendLocation", body=body)
96
+
97
+ def send_image(self, **body: Any) -> Any:
98
+ return self.request("POST", "/api/sendImage", body=body)
99
+
100
+ def send_voice(self, **body: Any) -> Any:
101
+ return self.request("POST", "/api/sendVoice", body=body)
102
+
103
+ def send_video(self, **body: Any) -> Any:
104
+ return self.request("POST", "/api/sendVideo", body=body)
105
+
106
+ def send_file(self, **body: Any) -> Any:
107
+ return self.request("POST", "/api/sendFile", body=body)
108
+
109
+ def send_event(self, body: Mapping[str, Any], session: str | None = None) -> Any:
110
+ return self.request("POST", f"/api/{_q(self._session(session))}/events", body=dict(body))
111
+
112
+ def get_messages(self, chat_id: str, *, session: str | None = None, **query: Any) -> Any:
113
+ return self.request("GET", f"/api/{_q(self._session(session))}/chats/{_q(chat_id)}/messages", query=query)
114
+
115
+ def edit_message(self, chat_id: str, message_id: str, body: Mapping[str, Any], *, session: str | None = None) -> Any:
116
+ return self.request("PUT", f"/api/{_q(self._session(session))}/chats/{_q(chat_id)}/messages/{_q(message_id)}", body=dict(body))
117
+
118
+ def delete_message(self, chat_id: str, message_id: str, *, session: str | None = None) -> Any:
119
+ return self.request("DELETE", f"/api/{_q(self._session(session))}/chats/{_q(chat_id)}/messages/{_q(message_id)}")
120
+
121
+ def list_groups(self, *, session: str | None = None) -> Any:
122
+ return self.request("GET", f"/api/{_q(self._session(session))}/groups")
123
+
124
+ def create_group(self, name: str, participants: list[str], *, session: str | None = None) -> Any:
125
+ return self.request("POST", f"/api/{_q(self._session(session))}/groups", body={"name": name, "participants": participants})
126
+
127
+ def list_group_participants(self, group_id: str, *, session: str | None = None) -> Any:
128
+ return self.request("GET", f"/api/{_q(self._session(session))}/groups/{_q(group_id)}/participants/v2")
129
+
130
+ def add_group_participants(self, group_id: str, participants: list[str], *, session: str | None = None) -> Any:
131
+ return self.request("POST", f"/api/{_q(self._session(session))}/groups/{_q(group_id)}/participants/add", body={"participants": participants})
132
+
133
+ def remove_group_participants(self, group_id: str, participants: list[str], *, session: str | None = None) -> Any:
134
+ return self.request("POST", f"/api/{_q(self._session(session))}/groups/{_q(group_id)}/participants/remove", body={"participants": participants})
135
+
136
+ def list_contacts(self, **query: Any) -> Any:
137
+ return self.request("GET", "/api/contacts/all", query=query)
138
+
139
+ def get_contact(self, **query: Any) -> Any:
140
+ return self.request("GET", "/api/contacts", query=query)
141
+
142
+ def update_contact(self, chat_id: str, body: Mapping[str, Any], *, session: str | None = None) -> Any:
143
+ return self.request("PUT", f"/api/{_q(self._session(session))}/contacts/{_q(chat_id)}", body=dict(body))
144
+
145
+ def check_contact_exists(self, **query: Any) -> Any:
146
+ return self.request("GET", "/api/contacts/check-exists", query=query)
147
+
148
+ def get_contact_about(self, **query: Any) -> Any:
149
+ return self.request("GET", "/api/contacts/about", query=query)
150
+
151
+ def get_contact_profile_picture(self, **query: Any) -> Any:
152
+ return self.request("GET", "/api/contacts/profile-picture", query=query)
153
+
154
+ def block_contact(self, contact_id: str) -> Any:
155
+ return self.request("POST", "/api/contacts/block", body={"contactId": contact_id})
156
+
157
+ def unblock_contact(self, contact_id: str) -> Any:
158
+ return self.request("POST", "/api/contacts/unblock", body={"contactId": contact_id})
159
+
160
+ def list_labels(self, *, session: str | None = None) -> Any:
161
+ return self.request("GET", f"/api/{_q(self._session(session))}/labels")
162
+
163
+ def create_label(self, name: str, color: int | None = None, *, session: str | None = None) -> Any:
164
+ return self.request("POST", f"/api/{_q(self._session(session))}/labels", body={"name": name, "color": color})
165
+
166
+ def update_label(self, label_id: str, body: Mapping[str, Any], *, session: str | None = None) -> Any:
167
+ return self.request("PUT", f"/api/{_q(self._session(session))}/labels/{_q(label_id)}", body=dict(body))
168
+
169
+ def delete_label(self, label_id: str, *, session: str | None = None) -> Any:
170
+ return self.request("DELETE", f"/api/{_q(self._session(session))}/labels/{_q(label_id)}")
171
+
172
+ def list_lids(self, *, session: str | None = None) -> Any:
173
+ return self.request("GET", f"/api/{_q(self._session(session))}/lids")
174
+
175
+ def count_lids(self, *, session: str | None = None) -> Any:
176
+ return self.request("GET", f"/api/{_q(self._session(session))}/lids/count")
177
+
178
+ def resolve_lid(self, lid: str, *, session: str | None = None) -> Any:
179
+ return self.request("GET", f"/api/{_q(self._session(session))}/lids/{_q(lid)}")
180
+
181
+ def resolve_phone_number_to_lid(self, phone_number: str, *, session: str | None = None) -> Any:
182
+ return self.request("GET", f"/api/{_q(self._session(session))}/lids/pn/{_q(phone_number)}")
183
+
184
+ def list_channels(self, *, session: str | None = None) -> Any:
185
+ return self.request("GET", f"/api/{_q(self._session(session))}/channels")
186
+
187
+ def create_channel(self, body: Mapping[str, Any], *, session: str | None = None) -> Any:
188
+ return self.request("POST", f"/api/{_q(self._session(session))}/channels", body=dict(body))
189
+
190
+ def get_channel(self, channel_id: str, *, session: str | None = None) -> Any:
191
+ return self.request("GET", f"/api/{_q(self._session(session))}/channels/{_q(channel_id)}")
192
+
193
+ def delete_channel(self, channel_id: str, *, session: str | None = None) -> Any:
194
+ return self.request("DELETE", f"/api/{_q(self._session(session))}/channels/{_q(channel_id)}")
195
+
196
+ def list_sessions(self, **query: Any) -> Any:
197
+ return self.request("GET", "/admin/sessions", query=query)
198
+
199
+ def create_session(self, body: Mapping[str, Any]) -> Any:
200
+ return self.request("POST", "/admin/sessions", body=dict(body))
201
+
202
+ def start_session(self, name: str) -> Any:
203
+ return self.request("POST", f"/admin/sessions/{_q(name)}/start")
204
+
205
+ def stop_session(self, name: str) -> Any:
206
+ return self.request("POST", f"/admin/sessions/{_q(name)}/stop")
207
+
208
+ def restart_session(self, name: str) -> Any:
209
+ return self.request("POST", f"/admin/sessions/{_q(name)}/restart")
210
+
211
+ def _session(self, session: str | None) -> str:
212
+ selected = session or self.session
213
+ if not selected:
214
+ raise ValueError("This method requires a session. Pass session to the client or method.")
215
+ return selected
216
+
217
+
218
+ def _decode_response(data: bytes, content_type: str) -> Any:
219
+ if not data:
220
+ return None
221
+ text = data.decode("utf-8")
222
+ if "application/json" in content_type:
223
+ return json.loads(text)
224
+ return text
225
+
226
+
227
+ def _q(value: str) -> str:
228
+ return quote(value, safe="")
229
+
230
+
231
+ def _read_upload_file(file: str | os.PathLike[str] | BinaryIO, filename: str | None) -> tuple[str, bytes]:
232
+ if isinstance(file, (str, os.PathLike)):
233
+ path = Path(file)
234
+ return filename or path.name, path.read_bytes()
235
+ return filename or getattr(file, "name", "upload.bin"), file.read()
236
+
237
+
238
+ def _multipart_body(boundary: str, field: str, filename: str, content_type: str, data: bytes) -> bytes:
239
+ return b"".join(
240
+ [
241
+ f"--{boundary}\r\n".encode(),
242
+ f'Content-Disposition: form-data; name="{field}"; filename="{filename}"\r\n'.encode(),
243
+ f"Content-Type: {content_type}\r\n\r\n".encode(),
244
+ data,
245
+ f"\r\n--{boundary}--\r\n".encode(),
246
+ ]
247
+ )
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: waappa-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Waappa API.
5
+ Author: Waappa
6
+ License: MIT
7
+ Keywords: waappa,whatsapp,waha,sdk
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # Waappa Python SDK
22
+
23
+ Official Python SDK for the Waappa API.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install waappa-sdk
29
+ ```
30
+
31
+ Requires Python 3.9 or newer.
32
+
33
+ ## Quick Start
34
+
35
+ ```python
36
+ from waappa import WaappaClient
37
+
38
+ waappa = WaappaClient(
39
+ api_key="waappa_session_api_key",
40
+ session="default",
41
+ )
42
+
43
+ waappa.send_text(
44
+ chatId="919876543210@c.us",
45
+ text="Hello from Waappa",
46
+ )
47
+ ```
48
+
49
+ The SDK sends the API key as the `Authorization` header. By default it uses:
50
+
51
+ ```text
52
+ https://api.waappa.com
53
+ ```
54
+
55
+ Use `base_url` for local or private deployments:
56
+
57
+ ```python
58
+ waappa = WaappaClient(
59
+ api_key="waappa_session_api_key",
60
+ session="default",
61
+ base_url="http://localhost:3001",
62
+ )
63
+ ```
64
+
65
+ ## Messages
66
+
67
+ ```python
68
+ waappa.send_image(
69
+ chatId="919876543210@c.us",
70
+ caption="Invoice",
71
+ file={
72
+ "mimetype": "image/jpeg",
73
+ "filename": "invoice.jpg",
74
+ "url": "https://example.com/invoice.jpg",
75
+ },
76
+ )
77
+
78
+ waappa.send_poll(
79
+ chatId="919876543210@c.us",
80
+ poll={
81
+ "name": "Choose one",
82
+ "options": ["A", "B"],
83
+ "multipleAnswers": False,
84
+ },
85
+ )
86
+ ```
87
+
88
+ Supported message helpers:
89
+
90
+ - `send_text`
91
+ - `send_image`
92
+ - `send_voice`
93
+ - `send_video`
94
+ - `send_file`
95
+ - `send_poll`
96
+ - `send_list`
97
+ - `send_contact_vcard`
98
+ - `send_location`
99
+ - `send_event`
100
+ - `edit_message`
101
+ - `delete_message`
102
+ - `get_messages`
103
+
104
+ ## Media Upload
105
+
106
+ ```python
107
+ uploaded = waappa.upload("invoice.jpg")
108
+ ```
109
+
110
+ Use the returned URL in `send_image`, `send_video`, `send_voice`, or `send_file`.
111
+
112
+ ## Groups, Contacts, Labels, LIDs, Channels
113
+
114
+ ```python
115
+ waappa.create_group("Support", ["919876543210@c.us"])
116
+
117
+ contacts = waappa.list_contacts()
118
+ labels = waappa.list_labels()
119
+ channels = waappa.list_channels()
120
+ ```
121
+
122
+ The client includes helpers for the selected Waappa API surface: groups, group participants, contacts, labels, LID/phone resolution, and channels.
123
+
124
+ ## Admin / Session Management
125
+
126
+ Session management methods require a master key:
127
+
128
+ ```python
129
+ admin = WaappaClient(api_key="mk_live_...")
130
+ sessions = admin.list_sessions()
131
+ ```
132
+
133
+ ## Errors
134
+
135
+ Failed API responses raise `WaappaError`:
136
+
137
+ ```python
138
+ from waappa import WaappaError
139
+
140
+ try:
141
+ waappa.send_text(chatId="bad", text="Hello")
142
+ except WaappaError as error:
143
+ print(error.status)
144
+ print(error.data)
145
+ ```
146
+
147
+ ## Development
148
+
149
+ ```bash
150
+ python -m compileall waappa
151
+ python -m pip wheel . --no-deps -w dist
152
+ ```
153
+
154
+ ## Publishing
155
+
156
+ ```bash
157
+ python -m build
158
+ python -m twine upload dist/*
159
+ ```
160
+
161
+ Before publishing, run a smoke test against a real Waappa API key and session.
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.cfg
5
+ waappa/__init__.py
6
+ waappa/client.py
7
+ waappa/py.typed
8
+ waappa_sdk.egg-info/PKG-INFO
9
+ waappa_sdk.egg-info/SOURCES.txt
10
+ waappa_sdk.egg-info/dependency_links.txt
11
+ waappa_sdk.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ waappa