openwa-sdk 1.0.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,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: openwa-sdk
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for OpenWA WhatsApp API Gateway
5
+ Author: OpenWA Contributors
6
+ License: MIT
7
+ Keywords: whatsapp,api,sdk,openwa,gateway
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: httpx>=0.25.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest>=7.0; extra == "dev"
13
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
14
+
15
+ # OpenWA Python SDK
16
+
17
+ The official Python client library for the [OpenWA](https://github.com/bonheurNE07/OpenWA-Python) REST API Gateway.
18
+
19
+ This SDK allows you to easily manage WhatsApp sessions, send text/media messages, and interact with WhatsApp groups natively in Python. It supports both **Synchronous** and **Asynchronous** workflows out of the box!
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install openwa-sdk
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```python
30
+ from openwa import OpenWAClient
31
+ import asyncio
32
+
33
+ # Initialize the client (points to your self-hosted OpenWA Gateway)
34
+ client = OpenWAClient(
35
+ base_url="http://localhost:2785",
36
+ api_key="secret-key"
37
+ )
38
+
39
+ # --- Synchronous Example ---
40
+ # 1. Create a session
41
+ session = client.sessions.create("my-session")
42
+ print(f"Session Created: {session}")
43
+
44
+ # 2. Start the session (returns QR code in the terminal)
45
+ client.sessions.start("my-session")
46
+
47
+ # 3. Send a message
48
+ client.messages.send_text("my-session", {
49
+ "chatId": "1234567890@c.us",
50
+ "text": "Hello from Python!"
51
+ })
52
+
53
+ # --- Asynchronous Example ---
54
+ async def main():
55
+ async_client = client.get_async_client()
56
+
57
+ # Send a message asynchronously
58
+ await async_client.messages.send_text("my-session", {
59
+ "chatId": "1234567890@c.us",
60
+ "text": "Hello async world!"
61
+ })
62
+
63
+ asyncio.run(main())
64
+ ```
65
+
66
+ ## Features
67
+ * **Fully Typed**: Written with type hints for excellent IDE autocomplete.
68
+ * **Sync & Async**: Backed by `httpx`, giving you both blocking and non-blocking clients.
69
+ * **Zero Overhead**: Directly maps to the OpenWA OpenAPI specification.
70
+
71
+ ## License
72
+ MIT License
@@ -0,0 +1,58 @@
1
+ # OpenWA Python SDK
2
+
3
+ The official Python client library for the [OpenWA](https://github.com/bonheurNE07/OpenWA-Python) REST API Gateway.
4
+
5
+ This SDK allows you to easily manage WhatsApp sessions, send text/media messages, and interact with WhatsApp groups natively in Python. It supports both **Synchronous** and **Asynchronous** workflows out of the box!
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install openwa-sdk
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from openwa import OpenWAClient
17
+ import asyncio
18
+
19
+ # Initialize the client (points to your self-hosted OpenWA Gateway)
20
+ client = OpenWAClient(
21
+ base_url="http://localhost:2785",
22
+ api_key="secret-key"
23
+ )
24
+
25
+ # --- Synchronous Example ---
26
+ # 1. Create a session
27
+ session = client.sessions.create("my-session")
28
+ print(f"Session Created: {session}")
29
+
30
+ # 2. Start the session (returns QR code in the terminal)
31
+ client.sessions.start("my-session")
32
+
33
+ # 3. Send a message
34
+ client.messages.send_text("my-session", {
35
+ "chatId": "1234567890@c.us",
36
+ "text": "Hello from Python!"
37
+ })
38
+
39
+ # --- Asynchronous Example ---
40
+ async def main():
41
+ async_client = client.get_async_client()
42
+
43
+ # Send a message asynchronously
44
+ await async_client.messages.send_text("my-session", {
45
+ "chatId": "1234567890@c.us",
46
+ "text": "Hello async world!"
47
+ })
48
+
49
+ asyncio.run(main())
50
+ ```
51
+
52
+ ## Features
53
+ * **Fully Typed**: Written with type hints for excellent IDE autocomplete.
54
+ * **Sync & Async**: Backed by `httpx`, giving you both blocking and non-blocking clients.
55
+ * **Zero Overhead**: Directly maps to the OpenWA OpenAPI specification.
56
+
57
+ ## License
58
+ MIT License
@@ -0,0 +1,473 @@
1
+ """
2
+ OpenWA Python SDK
3
+
4
+ Official client library for the OpenWA WhatsApp API Gateway.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from dataclasses import dataclass
11
+ from typing import Any, Optional
12
+
13
+
14
+ class OpenWAError(Exception):
15
+ """Base exception for OpenWA SDK."""
16
+
17
+
18
+ class OpenWAAPIError(OpenWAError):
19
+ """API returned an error response."""
20
+
21
+ def __init__(self, status_code: int, message: str) -> None:
22
+ self.status_code = status_code
23
+ self.message = message
24
+ super().__init__(f"API Error {status_code}: {message}")
25
+
26
+
27
+ @dataclass
28
+ class OpenWAClientConfig:
29
+ """Configuration for the OpenWA client."""
30
+
31
+ base_url: str
32
+ api_key: str
33
+ timeout: float = 30.0
34
+
35
+
36
+ @dataclass
37
+ class MessageResponse:
38
+ message_id: str
39
+ timestamp: int
40
+
41
+
42
+ class _BaseClient:
43
+ def __init__(
44
+ self,
45
+ base_url: Optional[str] = None,
46
+ api_key: Optional[str] = None,
47
+ timeout: float = 30.0,
48
+ ) -> None:
49
+ url = base_url or os.getenv("OPENWA_BASE_URL")
50
+ key = api_key or os.getenv("OPENWA_API_KEY")
51
+ if not url:
52
+ raise ValueError(
53
+ "base_url must be provided or set via OPENWA_BASE_URL environment variable."
54
+ )
55
+ if not key:
56
+ raise ValueError(
57
+ "api_key must be provided or set via OPENWA_API_KEY environment variable."
58
+ )
59
+
60
+ self.config = OpenWAClientConfig(
61
+ base_url=url.rstrip("/"),
62
+ api_key=key,
63
+ timeout=timeout,
64
+ )
65
+
66
+ def _handle_response(self, response: Any) -> Any:
67
+ if 400 <= response.status_code < 600:
68
+ try:
69
+ error_data = response.json()
70
+ msg = (
71
+ error_data.get("detail")
72
+ or error_data.get("message")
73
+ or response.text
74
+ )
75
+ except Exception:
76
+ msg = response.text
77
+ raise OpenWAAPIError(response.status_code, msg)
78
+
79
+ if response.status_code == 204:
80
+ return None
81
+ return response.json()
82
+
83
+
84
+ class OpenWAClient(_BaseClient):
85
+ """Synchronous OpenWA API client."""
86
+
87
+ @property
88
+ def sessions(self) -> "_SessionsResource":
89
+ return _SessionsResource(self)
90
+
91
+ @property
92
+ def messages(self) -> "_MessagesResource":
93
+ return _MessagesResource(self)
94
+
95
+ @property
96
+ def webhooks(self) -> "_WebhooksResource":
97
+ return _WebhooksResource(self)
98
+
99
+ @property
100
+ def api_keys(self) -> "_ApiKeysResource":
101
+ return _ApiKeysResource(self)
102
+
103
+ @property
104
+ def contacts(self) -> "_ContactsResource":
105
+ return _ContactsResource(self)
106
+
107
+ @property
108
+ def groups(self) -> "_GroupsResource":
109
+ return _GroupsResource(self)
110
+
111
+ def _request(self, method: str, path: str, json: Any = None) -> Any:
112
+ try:
113
+ import httpx
114
+ except ImportError:
115
+ raise ImportError("httpx is required. Install with: pip install httpx")
116
+
117
+ with httpx.Client(timeout=self.config.timeout) as client:
118
+ request_kwargs = {"json": json} if json is not None else {}
119
+ if method == "DELETE" and json is not None:
120
+ request_kwargs = {
121
+ "request": client.build_request(
122
+ "DELETE",
123
+ f"{self.config.base_url}{path}",
124
+ json=json,
125
+ headers={
126
+ "Content-Type": "application/json",
127
+ "X-API-Key": self.config.api_key,
128
+ },
129
+ )
130
+ }
131
+ response = client.send(request_kwargs["request"])
132
+ else:
133
+ response = client.request(
134
+ method,
135
+ f"{self.config.base_url}{path}",
136
+ headers={
137
+ "Content-Type": "application/json",
138
+ "X-API-Key": self.config.api_key,
139
+ },
140
+ **request_kwargs,
141
+ )
142
+ return self._handle_response(response)
143
+
144
+
145
+ class AsyncOpenWAClient(_BaseClient):
146
+ """Asynchronous OpenWA API client."""
147
+
148
+ @property
149
+ def sessions(self) -> "_AsyncSessionsResource":
150
+ return _AsyncSessionsResource(self)
151
+
152
+ @property
153
+ def messages(self) -> "_AsyncMessagesResource":
154
+ return _AsyncMessagesResource(self)
155
+
156
+ @property
157
+ def webhooks(self) -> "_AsyncWebhooksResource":
158
+ return _AsyncWebhooksResource(self)
159
+
160
+ @property
161
+ def api_keys(self) -> "_AsyncApiKeysResource":
162
+ return _AsyncApiKeysResource(self)
163
+
164
+ @property
165
+ def contacts(self) -> "_AsyncContactsResource":
166
+ return _AsyncContactsResource(self)
167
+
168
+ @property
169
+ def groups(self) -> "_AsyncGroupsResource":
170
+ return _AsyncGroupsResource(self)
171
+
172
+ async def _request(self, method: str, path: str, json: Any = None) -> Any:
173
+ try:
174
+ import httpx
175
+ except ImportError:
176
+ raise ImportError("httpx is required. Install with: pip install httpx")
177
+
178
+ async with httpx.AsyncClient(timeout=self.config.timeout) as client:
179
+ request_kwargs = {"json": json} if json is not None else {}
180
+ if method == "DELETE" and json is not None:
181
+ req = client.build_request(
182
+ "DELETE",
183
+ f"{self.config.base_url}{path}",
184
+ json=json,
185
+ headers={
186
+ "Content-Type": "application/json",
187
+ "X-API-Key": self.config.api_key,
188
+ },
189
+ )
190
+ response = await client.send(req)
191
+ else:
192
+ response = await client.request(
193
+ method,
194
+ f"{self.config.base_url}{path}",
195
+ headers={
196
+ "Content-Type": "application/json",
197
+ "X-API-Key": self.config.api_key,
198
+ },
199
+ **request_kwargs,
200
+ )
201
+ return self._handle_response(response)
202
+
203
+
204
+ class _SessionsResource:
205
+ def __init__(self, client: OpenWAClient) -> None:
206
+ self._client = client
207
+
208
+ def list(self) -> list[dict]:
209
+ return self._client._request("GET", "/api/sessions")
210
+
211
+ def get(self, session_id: str) -> dict:
212
+ return self._client._request("GET", f"/api/sessions/{session_id}")
213
+
214
+ def create(self, name: str) -> dict:
215
+ return self._client._request("POST", "/api/sessions", {"name": name})
216
+
217
+ def start(self, session_id: str) -> dict:
218
+ return self._client._request("POST", f"/api/sessions/{session_id}/start")
219
+
220
+ def stop(self, session_id: str) -> dict:
221
+ return self._client._request("POST", f"/api/sessions/{session_id}/stop")
222
+
223
+ def delete(self, session_id: str) -> None:
224
+ self._client._request("DELETE", f"/api/sessions/{session_id}")
225
+
226
+
227
+ class _AsyncSessionsResource:
228
+ def __init__(self, client: AsyncOpenWAClient) -> None:
229
+ self._client = client
230
+
231
+ async def list(self) -> list[dict]:
232
+ return await self._client._request("GET", "/api/sessions")
233
+
234
+ async def get(self, session_id: str) -> dict:
235
+ return await self._client._request("GET", f"/api/sessions/{session_id}")
236
+
237
+ async def create(self, name: str) -> dict:
238
+ return await self._client._request("POST", "/api/sessions", {"name": name})
239
+
240
+ async def start(self, session_id: str) -> dict:
241
+ return await self._client._request("POST", f"/api/sessions/{session_id}/start")
242
+
243
+ async def stop(self, session_id: str) -> dict:
244
+ return await self._client._request("POST", f"/api/sessions/{session_id}/stop")
245
+
246
+ async def delete(self, session_id: str) -> None:
247
+ await self._client._request("DELETE", f"/api/sessions/{session_id}")
248
+
249
+
250
+ class _MessagesResource:
251
+ def __init__(self, client: OpenWAClient) -> None:
252
+ self._client = client
253
+
254
+ def list(self, session_id: str) -> list[dict]:
255
+ return self._client._request("GET", f"/api/sessions/{session_id}/messages")
256
+
257
+ def send_text(self, session_id: str, data: dict[str, str]) -> MessageResponse:
258
+ res = self._client._request(
259
+ "POST", f"/api/sessions/{session_id}/messages/send-text", data
260
+ )
261
+ return MessageResponse(res["messageId"], res["timestamp"])
262
+
263
+
264
+ class _AsyncMessagesResource:
265
+ def __init__(self, client: AsyncOpenWAClient) -> None:
266
+ self._client = client
267
+
268
+ async def list(self, session_id: str) -> list[dict]:
269
+ return await self._client._request(
270
+ "GET", f"/api/sessions/{session_id}/messages"
271
+ )
272
+
273
+ async def send_text(self, session_id: str, data: dict[str, str]) -> MessageResponse:
274
+ res = await self._client._request(
275
+ "POST", f"/api/sessions/{session_id}/messages/send-text", data
276
+ )
277
+ return MessageResponse(res["messageId"], res["timestamp"])
278
+
279
+
280
+ class _WebhooksResource:
281
+ def __init__(self, client: OpenWAClient) -> None:
282
+ self._client = client
283
+
284
+ def list_all(self) -> list[dict]:
285
+ return self._client._request("GET", "/api/webhooks")
286
+
287
+ def create(self, session_id: str, data: dict) -> dict:
288
+ return self._client._request(
289
+ "POST", f"/api/sessions/{session_id}/webhooks", data
290
+ )
291
+
292
+ def update(self, session_id: str, webhook_id: str, data: dict) -> dict:
293
+ return self._client._request(
294
+ "PUT", f"/api/sessions/{session_id}/webhooks/{webhook_id}", data
295
+ )
296
+
297
+ def delete(self, session_id: str, webhook_id: str) -> None:
298
+ self._client._request(
299
+ "DELETE", f"/api/sessions/{session_id}/webhooks/{webhook_id}"
300
+ )
301
+
302
+
303
+ class _AsyncWebhooksResource:
304
+ def __init__(self, client: AsyncOpenWAClient) -> None:
305
+ self._client = client
306
+
307
+ async def list_all(self) -> list[dict]:
308
+ return await self._client._request("GET", "/api/webhooks")
309
+
310
+ async def create(self, session_id: str, data: dict) -> dict:
311
+ return await self._client._request(
312
+ "POST", f"/api/sessions/{session_id}/webhooks", data
313
+ )
314
+
315
+ async def update(self, session_id: str, webhook_id: str, data: dict) -> dict:
316
+ return await self._client._request(
317
+ "PUT", f"/api/sessions/{session_id}/webhooks/{webhook_id}", data
318
+ )
319
+
320
+ async def delete(self, session_id: str, webhook_id: str) -> None:
321
+ await self._client._request(
322
+ "DELETE", f"/api/sessions/{session_id}/webhooks/{webhook_id}"
323
+ )
324
+
325
+
326
+ class _ApiKeysResource:
327
+ def __init__(self, client: OpenWAClient) -> None:
328
+ self._client = client
329
+
330
+ def list(self) -> list[dict]:
331
+ return self._client._request("GET", "/api/auth/api-keys")
332
+
333
+ def create(self, data: dict) -> dict:
334
+ return self._client._request("POST", "/api/auth/api-keys", data)
335
+
336
+ def revoke(self, key_id: str) -> dict:
337
+ return self._client._request("POST", f"/api/auth/api-keys/{key_id}/revoke")
338
+
339
+ def rotate(self, key_id: str) -> dict:
340
+ return self._client._request("POST", f"/api/auth/api-keys/{key_id}/rotate")
341
+
342
+ def delete(self, key_id: str) -> None:
343
+ self._client._request("DELETE", f"/api/auth/api-keys/{key_id}")
344
+
345
+
346
+ class _AsyncApiKeysResource:
347
+ def __init__(self, client: AsyncOpenWAClient) -> None:
348
+ self._client = client
349
+
350
+ async def list(self) -> list[dict]:
351
+ return await self._client._request("GET", "/api/auth/api-keys")
352
+
353
+ async def create(self, data: dict) -> dict:
354
+ return await self._client._request("POST", "/api/auth/api-keys", data)
355
+
356
+ async def revoke(self, key_id: str) -> dict:
357
+ return await self._client._request(
358
+ "POST", f"/api/auth/api-keys/{key_id}/revoke"
359
+ )
360
+
361
+ async def rotate(self, key_id: str) -> dict:
362
+ return await self._client._request(
363
+ "POST", f"/api/auth/api-keys/{key_id}/rotate"
364
+ )
365
+
366
+ async def delete(self, key_id: str) -> None:
367
+ await self._client._request("DELETE", f"/api/auth/api-keys/{key_id}")
368
+
369
+
370
+ class _ContactsResource:
371
+ def __init__(self, client: OpenWAClient) -> None:
372
+ self._client = client
373
+
374
+ def list(self, session_id: str) -> list[dict]:
375
+ return self._client._request("GET", f"/api/sessions/{session_id}/contacts")
376
+
377
+ def get(self, session_id: str, contact_id: str) -> dict:
378
+ return self._client._request(
379
+ "GET", f"/api/sessions/{session_id}/contacts/{contact_id}"
380
+ )
381
+
382
+ def check_number(self, session_id: str, number: str) -> dict:
383
+ return self._client._request(
384
+ "GET", f"/api/sessions/{session_id}/contacts/check/{number}"
385
+ )
386
+
387
+ def block(self, session_id: str, contact_id: str) -> dict:
388
+ return self._client._request(
389
+ "POST", f"/api/sessions/{session_id}/contacts/{contact_id}/block"
390
+ )
391
+
392
+
393
+ class _AsyncContactsResource:
394
+ def __init__(self, client: AsyncOpenWAClient) -> None:
395
+ self._client = client
396
+
397
+ async def list(self, session_id: str) -> list[dict]:
398
+ return await self._client._request(
399
+ "GET", f"/api/sessions/{session_id}/contacts"
400
+ )
401
+
402
+ async def get(self, session_id: str, contact_id: str) -> dict:
403
+ return await self._client._request(
404
+ "GET", f"/api/sessions/{session_id}/contacts/{contact_id}"
405
+ )
406
+
407
+ async def check_number(self, session_id: str, number: str) -> dict:
408
+ return await self._client._request(
409
+ "GET", f"/api/sessions/{session_id}/contacts/check/{number}"
410
+ )
411
+
412
+ async def block(self, session_id: str, contact_id: str) -> dict:
413
+ return await self._client._request(
414
+ "POST", f"/api/sessions/{session_id}/contacts/{contact_id}/block"
415
+ )
416
+
417
+
418
+ class _GroupsResource:
419
+ def __init__(self, client: OpenWAClient) -> None:
420
+ self._client = client
421
+
422
+ def list(self, session_id: str) -> list[dict]:
423
+ return self._client._request("GET", f"/api/sessions/{session_id}/groups")
424
+
425
+ def create(self, session_id: str, data: dict) -> dict:
426
+ return self._client._request("POST", f"/api/sessions/{session_id}/groups", data)
427
+
428
+ def add_participants(self, session_id: str, group_id: str, data: dict) -> dict:
429
+ return self._client._request(
430
+ "POST", f"/api/sessions/{session_id}/groups/{group_id}/participants", data
431
+ )
432
+
433
+ def remove_participants(self, session_id: str, group_id: str, data: dict) -> dict:
434
+ return self._client._request(
435
+ "DELETE", f"/api/sessions/{session_id}/groups/{group_id}/participants", data
436
+ )
437
+
438
+ def set_subject(self, session_id: str, group_id: str, data: dict) -> dict:
439
+ return self._client._request(
440
+ "PUT", f"/api/sessions/{session_id}/groups/{group_id}/subject", data
441
+ )
442
+
443
+
444
+ class _AsyncGroupsResource:
445
+ def __init__(self, client: AsyncOpenWAClient) -> None:
446
+ self._client = client
447
+
448
+ async def list(self, session_id: str) -> list[dict]:
449
+ return await self._client._request("GET", f"/api/sessions/{session_id}/groups")
450
+
451
+ async def create(self, session_id: str, data: dict) -> dict:
452
+ return await self._client._request(
453
+ "POST", f"/api/sessions/{session_id}/groups", data
454
+ )
455
+
456
+ async def add_participants(
457
+ self, session_id: str, group_id: str, data: dict
458
+ ) -> dict:
459
+ return await self._client._request(
460
+ "POST", f"/api/sessions/{session_id}/groups/{group_id}/participants", data
461
+ )
462
+
463
+ async def remove_participants(
464
+ self, session_id: str, group_id: str, data: dict
465
+ ) -> dict:
466
+ return await self._client._request(
467
+ "DELETE", f"/api/sessions/{session_id}/groups/{group_id}/participants", data
468
+ )
469
+
470
+ async def set_subject(self, session_id: str, group_id: str, data: dict) -> dict:
471
+ return await self._client._request(
472
+ "PUT", f"/api/sessions/{session_id}/groups/{group_id}/subject", data
473
+ )
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: openwa-sdk
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for OpenWA WhatsApp API Gateway
5
+ Author: OpenWA Contributors
6
+ License: MIT
7
+ Keywords: whatsapp,api,sdk,openwa,gateway
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: httpx>=0.25.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest>=7.0; extra == "dev"
13
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
14
+
15
+ # OpenWA Python SDK
16
+
17
+ The official Python client library for the [OpenWA](https://github.com/bonheurNE07/OpenWA-Python) REST API Gateway.
18
+
19
+ This SDK allows you to easily manage WhatsApp sessions, send text/media messages, and interact with WhatsApp groups natively in Python. It supports both **Synchronous** and **Asynchronous** workflows out of the box!
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install openwa-sdk
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```python
30
+ from openwa import OpenWAClient
31
+ import asyncio
32
+
33
+ # Initialize the client (points to your self-hosted OpenWA Gateway)
34
+ client = OpenWAClient(
35
+ base_url="http://localhost:2785",
36
+ api_key="secret-key"
37
+ )
38
+
39
+ # --- Synchronous Example ---
40
+ # 1. Create a session
41
+ session = client.sessions.create("my-session")
42
+ print(f"Session Created: {session}")
43
+
44
+ # 2. Start the session (returns QR code in the terminal)
45
+ client.sessions.start("my-session")
46
+
47
+ # 3. Send a message
48
+ client.messages.send_text("my-session", {
49
+ "chatId": "1234567890@c.us",
50
+ "text": "Hello from Python!"
51
+ })
52
+
53
+ # --- Asynchronous Example ---
54
+ async def main():
55
+ async_client = client.get_async_client()
56
+
57
+ # Send a message asynchronously
58
+ await async_client.messages.send_text("my-session", {
59
+ "chatId": "1234567890@c.us",
60
+ "text": "Hello async world!"
61
+ })
62
+
63
+ asyncio.run(main())
64
+ ```
65
+
66
+ ## Features
67
+ * **Fully Typed**: Written with type hints for excellent IDE autocomplete.
68
+ * **Sync & Async**: Backed by `httpx`, giving you both blocking and non-blocking clients.
69
+ * **Zero Overhead**: Directly maps to the OpenWA OpenAPI specification.
70
+
71
+ ## License
72
+ MIT License
@@ -0,0 +1,8 @@
1
+ README.md
2
+ pyproject.toml
3
+ openwa/__init__.py
4
+ openwa_sdk.egg-info/PKG-INFO
5
+ openwa_sdk.egg-info/SOURCES.txt
6
+ openwa_sdk.egg-info/dependency_links.txt
7
+ openwa_sdk.egg-info/requires.txt
8
+ openwa_sdk.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ httpx>=0.25.0
2
+
3
+ [dev]
4
+ pytest>=7.0
5
+ pytest-asyncio>=0.23
@@ -0,0 +1 @@
1
+ openwa
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "openwa-sdk"
7
+ version = "1.0.0"
8
+ description = "Official Python SDK for OpenWA WhatsApp API Gateway"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ { name = "OpenWA Contributors" }
14
+ ]
15
+ keywords = ["whatsapp", "api", "sdk", "openwa", "gateway"]
16
+
17
+ dependencies = [
18
+ "httpx>=0.25.0",
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ dev = [
23
+ "pytest>=7.0",
24
+ "pytest-asyncio>=0.23",
25
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+