multiwa 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,81 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnpm-store/
4
+
5
+ # Build outputs
6
+ dist/
7
+ .next/
8
+ .turbo/
9
+ *.tsbuildinfo
10
+
11
+ # TypeScript compiled output in src directories
12
+ apps/*/src/**/*.js
13
+ apps/*/src/**/*.d.ts
14
+ apps/*/src/**/*.d.ts.map
15
+ apps/*/src/**/*.js.map
16
+ packages/*/src/**/*.js
17
+ packages/*/src/**/*.d.ts
18
+ packages/*/src/**/*.d.ts.map
19
+ packages/*/src/**/*.js.map
20
+
21
+ # Environment
22
+ .env
23
+ .env.local
24
+ .env.*.local
25
+ .env.production
26
+ .env.staging
27
+ packages/database/.env
28
+
29
+ # SSL Certificates
30
+ *.pem
31
+ *.key
32
+ *.crt
33
+ docker/nginx/ssl/
34
+
35
+ # IDE
36
+ .vscode/
37
+ .idea/
38
+ *.swp
39
+ *.swo
40
+
41
+ # OS
42
+ .DS_Store
43
+ Thumbs.db
44
+
45
+ # Logs
46
+ logs/
47
+ *.log
48
+ npm-debug.log*
49
+ pnpm-debug.log*
50
+
51
+ # Testing
52
+ coverage/
53
+
54
+ # Python cache
55
+ __pycache__/
56
+ *.pyc
57
+
58
+ # WhatsApp sessions
59
+ sessions/
60
+ .wwebjs_auth/
61
+ .wwebjs_cache/
62
+
63
+ # Plugins runtime data
64
+ plugins/*/node_modules/
65
+
66
+ # Temporary
67
+ .tmp/
68
+ tmp/
69
+ temp/
70
+
71
+ # Local-only working notes (never public)
72
+ /findings.md
73
+ /progress.md
74
+ /task_plan.md
75
+ /docs/superpowers/
76
+
77
+ # Internal-only operational notes and SOPs (never public)
78
+ /architecture/
79
+
80
+ # Docusaurus
81
+ docs-site/.docusaurus/
multiwa-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MultiWA
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.
multiwa-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: multiwa
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the MultiWA WhatsApp Business API Gateway.
5
+ Project-URL: Homepage, https://github.com/ribato22/MultiWA/tree/main/packages/sdk-python#readme
6
+ Project-URL: Repository, https://github.com/ribato22/MultiWA
7
+ Project-URL: Issues, https://github.com/ribato22/MultiWA/issues
8
+ Project-URL: Changelog, https://github.com/ribato22/MultiWA/blob/main/CHANGELOG.md
9
+ Author: MultiWA Team
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,automation,gateway,messaging,multiwa,whatsapp,whatsapp-api
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Communications :: Chat
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Requires-Dist: httpx>=0.24.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: black>=23.0.0; extra == 'dev'
30
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
32
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # MultiWA Python SDK
37
+
38
+ Official Python SDK for [MultiWA](https://github.com/ribato22/multiwa) - WhatsApp Business API Gateway.
39
+
40
+ ## Installation
41
+
42
+ The SDK is available in this repository today. Public registry publishing
43
+ (`multiwa` on PyPI) is tracked as a release follow-up and is **not yet
44
+ verified**, so do not assume `pip install multiwa` resolves to this package
45
+ on the registry.
46
+
47
+ Until the registry release is verified, install from this repository:
48
+
49
+ ```bash
50
+ # From the MultiWA monorepo (recommended for contributors)
51
+ pip install -e packages/sdk-python
52
+
53
+ # From a git ref
54
+ pip install "multiwa @ git+https://github.com/ribato22/MultiWA.git#subdirectory=packages/sdk-python"
55
+ ```
56
+
57
+ ## Quick Start
58
+
59
+ ```python
60
+ from multiwa import MultiWA
61
+
62
+ # Initialize the client. base_url must include the API prefix /api/v1.
63
+ # Local dev: http://localhost:3000/api/v1
64
+ # Docker: http://localhost:3333/api/v1
65
+ # Prod: https://your-multiwa-instance.com/api/v1
66
+ client = MultiWA(
67
+ base_url="https://your-multiwa-instance.com/api/v1",
68
+ api_key="your-api-key",
69
+ )
70
+
71
+ # Send a text message
72
+ result = client.messages.send_text(
73
+ profile_id="your-profile-id",
74
+ to="6281234567890",
75
+ text="Hello from MultiWA Python SDK!"
76
+ )
77
+
78
+ print(result)
79
+ ```
80
+
81
+ ## Features
82
+
83
+ ### Messages
84
+
85
+ ```python
86
+ # Send text
87
+ client.messages.send_text(profile_id, to, text)
88
+
89
+ # Send image
90
+ client.messages.send_image(profile_id, to, url="https://...", caption="Check this!")
91
+
92
+ # Send video
93
+ client.messages.send_video(profile_id, to, url="https://...", caption="Watch this!")
94
+
95
+ # Send document
96
+ client.messages.send_document(profile_id, to, url="https://...", filename="report.pdf")
97
+
98
+ # Send location
99
+ client.messages.send_location(profile_id, to, latitude=-6.2088, longitude=106.8456)
100
+
101
+ # Send contact
102
+ client.messages.send_contact(profile_id, to, name="John Doe", phone="+6281234567890")
103
+
104
+ # Send poll
105
+ client.messages.send_poll(
106
+ profile_id, to,
107
+ question="What's your favorite color?",
108
+ options=["Red", "Green", "Blue"]
109
+ )
110
+ ```
111
+
112
+ ### Broadcasts
113
+
114
+ ```python
115
+ # Create broadcast
116
+ client.broadcasts.create(
117
+ profile_id="...",
118
+ name="Promo Campaign",
119
+ recipients=["6281234567890", "6281234567891"],
120
+ template_id="template-uuid"
121
+ )
122
+
123
+ # List broadcasts
124
+ broadcasts = client.broadcasts.list(profile_id)
125
+ ```
126
+
127
+ ### Contacts
128
+
129
+ ```python
130
+ # Create contact
131
+ client.contacts.create(
132
+ profile_id="...",
133
+ phone="6281234567890",
134
+ name="John Doe",
135
+ tags=["customer", "vip"]
136
+ )
137
+
138
+ # List contacts
139
+ contacts = client.contacts.list(profile_id)
140
+ ```
141
+
142
+ ### Webhooks
143
+
144
+ ```python
145
+ # Create webhook
146
+ client.webhooks.create(
147
+ profile_id="...",
148
+ url="https://your-webhook.com/whatsapp",
149
+ events=["message.received", "message.sent"]
150
+ )
151
+ ```
152
+
153
+ ## Async Support
154
+
155
+ ```python
156
+ import asyncio
157
+ from multiwa import AsyncMultiWA
158
+
159
+ async def main():
160
+ client = AsyncMultiWA(
161
+ base_url="https://your-multiwa-instance.com/api",
162
+ api_key="your-api-key"
163
+ )
164
+
165
+ result = await client.messages.send_text(
166
+ profile_id="...",
167
+ to="6281234567890",
168
+ text="Hello async!"
169
+ )
170
+ print(result)
171
+
172
+ asyncio.run(main())
173
+ ```
174
+
175
+ ## License
176
+
177
+ MIT - See [LICENSE](LICENSE) for details.
@@ -0,0 +1,142 @@
1
+ # MultiWA Python SDK
2
+
3
+ Official Python SDK for [MultiWA](https://github.com/ribato22/multiwa) - WhatsApp Business API Gateway.
4
+
5
+ ## Installation
6
+
7
+ The SDK is available in this repository today. Public registry publishing
8
+ (`multiwa` on PyPI) is tracked as a release follow-up and is **not yet
9
+ verified**, so do not assume `pip install multiwa` resolves to this package
10
+ on the registry.
11
+
12
+ Until the registry release is verified, install from this repository:
13
+
14
+ ```bash
15
+ # From the MultiWA monorepo (recommended for contributors)
16
+ pip install -e packages/sdk-python
17
+
18
+ # From a git ref
19
+ pip install "multiwa @ git+https://github.com/ribato22/MultiWA.git#subdirectory=packages/sdk-python"
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```python
25
+ from multiwa import MultiWA
26
+
27
+ # Initialize the client. base_url must include the API prefix /api/v1.
28
+ # Local dev: http://localhost:3000/api/v1
29
+ # Docker: http://localhost:3333/api/v1
30
+ # Prod: https://your-multiwa-instance.com/api/v1
31
+ client = MultiWA(
32
+ base_url="https://your-multiwa-instance.com/api/v1",
33
+ api_key="your-api-key",
34
+ )
35
+
36
+ # Send a text message
37
+ result = client.messages.send_text(
38
+ profile_id="your-profile-id",
39
+ to="6281234567890",
40
+ text="Hello from MultiWA Python SDK!"
41
+ )
42
+
43
+ print(result)
44
+ ```
45
+
46
+ ## Features
47
+
48
+ ### Messages
49
+
50
+ ```python
51
+ # Send text
52
+ client.messages.send_text(profile_id, to, text)
53
+
54
+ # Send image
55
+ client.messages.send_image(profile_id, to, url="https://...", caption="Check this!")
56
+
57
+ # Send video
58
+ client.messages.send_video(profile_id, to, url="https://...", caption="Watch this!")
59
+
60
+ # Send document
61
+ client.messages.send_document(profile_id, to, url="https://...", filename="report.pdf")
62
+
63
+ # Send location
64
+ client.messages.send_location(profile_id, to, latitude=-6.2088, longitude=106.8456)
65
+
66
+ # Send contact
67
+ client.messages.send_contact(profile_id, to, name="John Doe", phone="+6281234567890")
68
+
69
+ # Send poll
70
+ client.messages.send_poll(
71
+ profile_id, to,
72
+ question="What's your favorite color?",
73
+ options=["Red", "Green", "Blue"]
74
+ )
75
+ ```
76
+
77
+ ### Broadcasts
78
+
79
+ ```python
80
+ # Create broadcast
81
+ client.broadcasts.create(
82
+ profile_id="...",
83
+ name="Promo Campaign",
84
+ recipients=["6281234567890", "6281234567891"],
85
+ template_id="template-uuid"
86
+ )
87
+
88
+ # List broadcasts
89
+ broadcasts = client.broadcasts.list(profile_id)
90
+ ```
91
+
92
+ ### Contacts
93
+
94
+ ```python
95
+ # Create contact
96
+ client.contacts.create(
97
+ profile_id="...",
98
+ phone="6281234567890",
99
+ name="John Doe",
100
+ tags=["customer", "vip"]
101
+ )
102
+
103
+ # List contacts
104
+ contacts = client.contacts.list(profile_id)
105
+ ```
106
+
107
+ ### Webhooks
108
+
109
+ ```python
110
+ # Create webhook
111
+ client.webhooks.create(
112
+ profile_id="...",
113
+ url="https://your-webhook.com/whatsapp",
114
+ events=["message.received", "message.sent"]
115
+ )
116
+ ```
117
+
118
+ ## Async Support
119
+
120
+ ```python
121
+ import asyncio
122
+ from multiwa import AsyncMultiWA
123
+
124
+ async def main():
125
+ client = AsyncMultiWA(
126
+ base_url="https://your-multiwa-instance.com/api",
127
+ api_key="your-api-key"
128
+ )
129
+
130
+ result = await client.messages.send_text(
131
+ profile_id="...",
132
+ to="6281234567890",
133
+ text="Hello async!"
134
+ )
135
+ print(result)
136
+
137
+ asyncio.run(main())
138
+ ```
139
+
140
+ ## License
141
+
142
+ MIT - See [LICENSE](LICENSE) for details.
@@ -0,0 +1,31 @@
1
+ """
2
+ MultiWA Python SDK
3
+
4
+ Official Python SDK for MultiWA - WhatsApp Business API Gateway.
5
+ """
6
+
7
+ from .client import MultiWA, AsyncMultiWA
8
+ from .webhooks import verify_webhook_signature
9
+ from .types import (
10
+ Message,
11
+ MessageResult,
12
+ Contact,
13
+ Broadcast,
14
+ Template,
15
+ Profile,
16
+ Webhook,
17
+ )
18
+
19
+ __version__ = "1.0.0"
20
+ __all__ = [
21
+ "MultiWA",
22
+ "AsyncMultiWA",
23
+ "Message",
24
+ "MessageResult",
25
+ "Contact",
26
+ "Broadcast",
27
+ "Template",
28
+ "Profile",
29
+ "Webhook",
30
+ "verify_webhook_signature",
31
+ ]
@@ -0,0 +1,147 @@
1
+ """
2
+ MultiWA Python SDK - Broadcasts Client
3
+
4
+ Client for managing broadcast campaigns.
5
+ """
6
+
7
+ from typing import Optional, List, Dict, Any
8
+ import httpx
9
+
10
+ from .types import Broadcast
11
+
12
+
13
+ class BroadcastsClient:
14
+ """Synchronous Broadcasts API client"""
15
+
16
+ def __init__(self, http: httpx.Client):
17
+ self._http = http
18
+
19
+ def create(
20
+ self,
21
+ profile_id: str,
22
+ name: str,
23
+ recipients: List[str],
24
+ template_id: Optional[str] = None,
25
+ message: Optional[str] = None,
26
+ schedule_at: Optional[str] = None,
27
+ ) -> Broadcast:
28
+ """Create a new broadcast campaign"""
29
+ response = self._http.post("/broadcasts", json={
30
+ "profileId": profile_id,
31
+ "name": name,
32
+ "recipients": recipients,
33
+ "templateId": template_id,
34
+ "message": message,
35
+ "scheduleAt": schedule_at,
36
+ })
37
+ response.raise_for_status()
38
+ return Broadcast(**response.json())
39
+
40
+ def get(self, broadcast_id: str) -> Broadcast:
41
+ """Get a broadcast by ID"""
42
+ response = self._http.get(f"/broadcasts/{broadcast_id}")
43
+ response.raise_for_status()
44
+ return Broadcast(**response.json())
45
+
46
+ def list(
47
+ self,
48
+ profile_id: str,
49
+ limit: int = 50,
50
+ offset: int = 0,
51
+ status: Optional[str] = None,
52
+ ) -> List[Broadcast]:
53
+ """List broadcasts for a profile"""
54
+ params: Dict[str, Any] = {
55
+ "limit": limit,
56
+ "offset": offset,
57
+ }
58
+ if status:
59
+ params["status"] = status
60
+
61
+ response = self._http.get(f"/broadcasts/profile/{profile_id}", params=params)
62
+ response.raise_for_status()
63
+ return [Broadcast(**b) for b in response.json()]
64
+
65
+ def start(self, broadcast_id: str) -> Broadcast:
66
+ """Start a broadcast"""
67
+ response = self._http.post(f"/broadcasts/{broadcast_id}/start")
68
+ response.raise_for_status()
69
+ return Broadcast(**response.json())
70
+
71
+ def pause(self, broadcast_id: str) -> Broadcast:
72
+ """Pause a broadcast"""
73
+ response = self._http.post(f"/broadcasts/{broadcast_id}/pause")
74
+ response.raise_for_status()
75
+ return Broadcast(**response.json())
76
+
77
+ def cancel(self, broadcast_id: str) -> Broadcast:
78
+ """Cancel a broadcast"""
79
+ response = self._http.post(f"/broadcasts/{broadcast_id}/cancel")
80
+ response.raise_for_status()
81
+ return Broadcast(**response.json())
82
+
83
+ def delete(self, broadcast_id: str) -> Dict[str, bool]:
84
+ """Delete a broadcast"""
85
+ response = self._http.delete(f"/broadcasts/{broadcast_id}")
86
+ response.raise_for_status()
87
+ return response.json()
88
+
89
+ def stats(self, broadcast_id: str) -> Dict[str, Any]:
90
+ """Get broadcast statistics"""
91
+ response = self._http.get(f"/broadcasts/{broadcast_id}/stats")
92
+ response.raise_for_status()
93
+ return response.json()
94
+
95
+
96
+ class AsyncBroadcastsClient:
97
+ """Asynchronous Broadcasts API client"""
98
+
99
+ def __init__(self, http: httpx.AsyncClient):
100
+ self._http = http
101
+
102
+ async def create(
103
+ self,
104
+ profile_id: str,
105
+ name: str,
106
+ recipients: List[str],
107
+ template_id: Optional[str] = None,
108
+ message: Optional[str] = None,
109
+ schedule_at: Optional[str] = None,
110
+ ) -> Broadcast:
111
+ """Create a new broadcast campaign"""
112
+ response = await self._http.post("/broadcasts", json={
113
+ "profileId": profile_id,
114
+ "name": name,
115
+ "recipients": recipients,
116
+ "templateId": template_id,
117
+ "message": message,
118
+ "scheduleAt": schedule_at,
119
+ })
120
+ response.raise_for_status()
121
+ return Broadcast(**response.json())
122
+
123
+ async def get(self, broadcast_id: str) -> Broadcast:
124
+ """Get a broadcast by ID"""
125
+ response = await self._http.get(f"/broadcasts/{broadcast_id}")
126
+ response.raise_for_status()
127
+ return Broadcast(**response.json())
128
+
129
+ async def list(
130
+ self,
131
+ profile_id: str,
132
+ limit: int = 50,
133
+ offset: int = 0,
134
+ ) -> List[Broadcast]:
135
+ """List broadcasts for a profile"""
136
+ response = await self._http.get(
137
+ f"/broadcasts/profile/{profile_id}",
138
+ params={"limit": limit, "offset": offset}
139
+ )
140
+ response.raise_for_status()
141
+ return [Broadcast(**b) for b in response.json()]
142
+
143
+ async def start(self, broadcast_id: str) -> Broadcast:
144
+ """Start a broadcast"""
145
+ response = await self._http.post(f"/broadcasts/{broadcast_id}/start")
146
+ response.raise_for_status()
147
+ return Broadcast(**response.json())