whatsapp-cloud-api-client 0.2.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.
- whatsapp_cloud_api_client-0.2.0/PKG-INFO +184 -0
- whatsapp_cloud_api_client-0.2.0/README.md +156 -0
- whatsapp_cloud_api_client-0.2.0/pyproject.toml +52 -0
- whatsapp_cloud_api_client-0.2.0/setup.cfg +4 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api/__init__.py +21 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api/client.py +534 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api/exceptions.py +26 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api/models.py +40 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api/webhook.py +34 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api_client.egg-info/PKG-INFO +184 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api_client.egg-info/SOURCES.txt +15 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api_client.egg-info/dependency_links.txt +1 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api_client.egg-info/requires.txt +9 -0
- whatsapp_cloud_api_client-0.2.0/src/whatsapp_cloud_api_client.egg-info/top_level.txt +1 -0
- whatsapp_cloud_api_client-0.2.0/tests/test_async_client.py +130 -0
- whatsapp_cloud_api_client-0.2.0/tests/test_client.py +159 -0
- whatsapp_cloud_api_client-0.2.0/tests/test_webhook.py +49 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: whatsapp-cloud-api-client
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Biblioteca Python para integração com a API Oficial do WhatsApp (Cloud API).
|
|
5
|
+
Author: Seu Nome
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/seu-usuario/whatsapp-cloud-api-client
|
|
8
|
+
Project-URL: Documentation, https://github.com/seu-usuario/whatsapp-cloud-api-client#readme
|
|
9
|
+
Project-URL: Issues, https://github.com/seu-usuario/whatsapp-cloud-api-client/issues
|
|
10
|
+
Keywords: whatsapp,whatsapp cloud api,meta,messaging,python
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: httpx<1.0.0,>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic<3.0.0,>=2.7.0
|
|
24
|
+
Requires-Dist: eval-type-backport>=0.2.0; python_version < "3.10"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest<9.0.0,>=8.2.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-asyncio<1.0.0,>=0.23.7; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# WhatsApp Cloud API Client (Python)
|
|
30
|
+
|
|
31
|
+
Biblioteca Python para integracao com a API Oficial do WhatsApp (Cloud API), com foco em simplicidade de uso em apps.
|
|
32
|
+
|
|
33
|
+
## Instalacao
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install whatsapp-cloud-api-client
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Para desenvolvimento local:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -e ".[dev]"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Uso rapido (sync)
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from whatsapp_cloud_api import WhatsAppClient
|
|
49
|
+
|
|
50
|
+
client = WhatsAppClient(
|
|
51
|
+
access_token="SEU_TOKEN",
|
|
52
|
+
phone_number_id="SEU_PHONE_NUMBER_ID",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
resp = client.send_text(
|
|
56
|
+
to="5511999999999",
|
|
57
|
+
body="Ola! Mensagem enviada via Cloud API.",
|
|
58
|
+
)
|
|
59
|
+
print(resp.model_dump())
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Uso rapido (async)
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import asyncio
|
|
66
|
+
from whatsapp_cloud_api import AsyncWhatsAppClient
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
async def main() -> None:
|
|
70
|
+
async with AsyncWhatsAppClient(
|
|
71
|
+
access_token="SEU_TOKEN",
|
|
72
|
+
phone_number_id="SEU_PHONE_NUMBER_ID",
|
|
73
|
+
) as client:
|
|
74
|
+
resp = await client.send_text(
|
|
75
|
+
to="5511999999999",
|
|
76
|
+
body="Mensagem async",
|
|
77
|
+
)
|
|
78
|
+
print(resp.model_dump())
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
asyncio.run(main())
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Modelos tipados (Pydantic)
|
|
85
|
+
|
|
86
|
+
Os metodos retornam modelos Pydantic:
|
|
87
|
+
|
|
88
|
+
- `SendMessageResponse`
|
|
89
|
+
- `MediaUploadResponse`
|
|
90
|
+
- `MediaInfoResponse`
|
|
91
|
+
- `MarkAsReadResponse`
|
|
92
|
+
|
|
93
|
+
## Retry, backoff e rate limit
|
|
94
|
+
|
|
95
|
+
O cliente possui retry configuravel para erros transientes (`429`, `500`, `502`, `503`, `504`).
|
|
96
|
+
|
|
97
|
+
Por padrao, retry roda apenas para `GET` para evitar duplicidade em envio de mensagem (`POST`).
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from whatsapp_cloud_api import WhatsAppClient
|
|
101
|
+
|
|
102
|
+
client = WhatsAppClient(
|
|
103
|
+
access_token="SEU_TOKEN",
|
|
104
|
+
phone_number_id="SEU_PHONE_NUMBER_ID",
|
|
105
|
+
max_retries=3,
|
|
106
|
+
backoff_factor=0.5,
|
|
107
|
+
max_backoff=8.0,
|
|
108
|
+
retry_methods={"GET", "POST"}, # habilite POST se quiser retry em envio
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Se a API retornar `Retry-After`, esse valor sera respeitado.
|
|
113
|
+
|
|
114
|
+
## Funcionalidades implementadas
|
|
115
|
+
|
|
116
|
+
- Envio de mensagem de texto
|
|
117
|
+
- Envio de mensagem template
|
|
118
|
+
- Envio de midia por `media_id` ou `link` (imagem, documento, video, audio, sticker)
|
|
119
|
+
- Upload de midia
|
|
120
|
+
- Marcar mensagem como lida
|
|
121
|
+
- Busca de informacoes de midia
|
|
122
|
+
- Validacao de assinatura de webhook (`X-Hub-Signature-256`)
|
|
123
|
+
- Cliente sincrono e assincrono
|
|
124
|
+
|
|
125
|
+
## Exemplo com Flask (webhook)
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from flask import Flask, request, jsonify
|
|
129
|
+
from whatsapp_cloud_api import verify_webhook_signature, verify_webhook_challenge
|
|
130
|
+
|
|
131
|
+
app = Flask(__name__)
|
|
132
|
+
APP_SECRET = "SEU_APP_SECRET"
|
|
133
|
+
VERIFY_TOKEN = "SEU_VERIFY_TOKEN"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@app.get("/webhook")
|
|
137
|
+
def webhook_verify():
|
|
138
|
+
ok, challenge = verify_webhook_challenge(
|
|
139
|
+
mode=request.args.get("hub.mode"),
|
|
140
|
+
token=request.args.get("hub.verify_token"),
|
|
141
|
+
challenge=request.args.get("hub.challenge"),
|
|
142
|
+
verify_token=VERIFY_TOKEN,
|
|
143
|
+
)
|
|
144
|
+
if not ok:
|
|
145
|
+
return "forbidden", 403
|
|
146
|
+
return challenge, 200
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@app.post("/webhook")
|
|
150
|
+
def webhook_receive():
|
|
151
|
+
if not verify_webhook_signature(
|
|
152
|
+
app_secret=APP_SECRET,
|
|
153
|
+
raw_body=request.get_data(),
|
|
154
|
+
x_hub_signature_256=request.headers.get("X-Hub-Signature-256", ""),
|
|
155
|
+
):
|
|
156
|
+
return "invalid signature", 401
|
|
157
|
+
|
|
158
|
+
data = request.get_json(silent=True) or {}
|
|
159
|
+
return jsonify({"ok": True, "received": bool(data)}), 200
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Rodar testes
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
pytest
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## CI e publicacao
|
|
169
|
+
|
|
170
|
+
- CI: `.github/workflows/ci.yml`
|
|
171
|
+
- Criacao de tag/release: `.github/workflows/release.yml`
|
|
172
|
+
- Publicacao PyPI: `.github/workflows/publish.yml`
|
|
173
|
+
|
|
174
|
+
Fluxo recomendado:
|
|
175
|
+
|
|
176
|
+
1. Execute o workflow `Create Release` e informe a tag (ex: `v0.2.0`).
|
|
177
|
+
2. O release publicado dispara `Publish to PyPI`.
|
|
178
|
+
3. Configure Trusted Publisher no PyPI para este repositorio (OIDC), sem token manual.
|
|
179
|
+
|
|
180
|
+
Opcional: se preferir token, adapte o workflow para usar `PYPI_API_TOKEN`.
|
|
181
|
+
|
|
182
|
+
## Licenca
|
|
183
|
+
|
|
184
|
+
MIT
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# WhatsApp Cloud API Client (Python)
|
|
2
|
+
|
|
3
|
+
Biblioteca Python para integracao com a API Oficial do WhatsApp (Cloud API), com foco em simplicidade de uso em apps.
|
|
4
|
+
|
|
5
|
+
## Instalacao
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install whatsapp-cloud-api-client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Para desenvolvimento local:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install -e ".[dev]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Uso rapido (sync)
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from whatsapp_cloud_api import WhatsAppClient
|
|
21
|
+
|
|
22
|
+
client = WhatsAppClient(
|
|
23
|
+
access_token="SEU_TOKEN",
|
|
24
|
+
phone_number_id="SEU_PHONE_NUMBER_ID",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
resp = client.send_text(
|
|
28
|
+
to="5511999999999",
|
|
29
|
+
body="Ola! Mensagem enviada via Cloud API.",
|
|
30
|
+
)
|
|
31
|
+
print(resp.model_dump())
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Uso rapido (async)
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import asyncio
|
|
38
|
+
from whatsapp_cloud_api import AsyncWhatsAppClient
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
async def main() -> None:
|
|
42
|
+
async with AsyncWhatsAppClient(
|
|
43
|
+
access_token="SEU_TOKEN",
|
|
44
|
+
phone_number_id="SEU_PHONE_NUMBER_ID",
|
|
45
|
+
) as client:
|
|
46
|
+
resp = await client.send_text(
|
|
47
|
+
to="5511999999999",
|
|
48
|
+
body="Mensagem async",
|
|
49
|
+
)
|
|
50
|
+
print(resp.model_dump())
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
asyncio.run(main())
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Modelos tipados (Pydantic)
|
|
57
|
+
|
|
58
|
+
Os metodos retornam modelos Pydantic:
|
|
59
|
+
|
|
60
|
+
- `SendMessageResponse`
|
|
61
|
+
- `MediaUploadResponse`
|
|
62
|
+
- `MediaInfoResponse`
|
|
63
|
+
- `MarkAsReadResponse`
|
|
64
|
+
|
|
65
|
+
## Retry, backoff e rate limit
|
|
66
|
+
|
|
67
|
+
O cliente possui retry configuravel para erros transientes (`429`, `500`, `502`, `503`, `504`).
|
|
68
|
+
|
|
69
|
+
Por padrao, retry roda apenas para `GET` para evitar duplicidade em envio de mensagem (`POST`).
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from whatsapp_cloud_api import WhatsAppClient
|
|
73
|
+
|
|
74
|
+
client = WhatsAppClient(
|
|
75
|
+
access_token="SEU_TOKEN",
|
|
76
|
+
phone_number_id="SEU_PHONE_NUMBER_ID",
|
|
77
|
+
max_retries=3,
|
|
78
|
+
backoff_factor=0.5,
|
|
79
|
+
max_backoff=8.0,
|
|
80
|
+
retry_methods={"GET", "POST"}, # habilite POST se quiser retry em envio
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Se a API retornar `Retry-After`, esse valor sera respeitado.
|
|
85
|
+
|
|
86
|
+
## Funcionalidades implementadas
|
|
87
|
+
|
|
88
|
+
- Envio de mensagem de texto
|
|
89
|
+
- Envio de mensagem template
|
|
90
|
+
- Envio de midia por `media_id` ou `link` (imagem, documento, video, audio, sticker)
|
|
91
|
+
- Upload de midia
|
|
92
|
+
- Marcar mensagem como lida
|
|
93
|
+
- Busca de informacoes de midia
|
|
94
|
+
- Validacao de assinatura de webhook (`X-Hub-Signature-256`)
|
|
95
|
+
- Cliente sincrono e assincrono
|
|
96
|
+
|
|
97
|
+
## Exemplo com Flask (webhook)
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from flask import Flask, request, jsonify
|
|
101
|
+
from whatsapp_cloud_api import verify_webhook_signature, verify_webhook_challenge
|
|
102
|
+
|
|
103
|
+
app = Flask(__name__)
|
|
104
|
+
APP_SECRET = "SEU_APP_SECRET"
|
|
105
|
+
VERIFY_TOKEN = "SEU_VERIFY_TOKEN"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@app.get("/webhook")
|
|
109
|
+
def webhook_verify():
|
|
110
|
+
ok, challenge = verify_webhook_challenge(
|
|
111
|
+
mode=request.args.get("hub.mode"),
|
|
112
|
+
token=request.args.get("hub.verify_token"),
|
|
113
|
+
challenge=request.args.get("hub.challenge"),
|
|
114
|
+
verify_token=VERIFY_TOKEN,
|
|
115
|
+
)
|
|
116
|
+
if not ok:
|
|
117
|
+
return "forbidden", 403
|
|
118
|
+
return challenge, 200
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@app.post("/webhook")
|
|
122
|
+
def webhook_receive():
|
|
123
|
+
if not verify_webhook_signature(
|
|
124
|
+
app_secret=APP_SECRET,
|
|
125
|
+
raw_body=request.get_data(),
|
|
126
|
+
x_hub_signature_256=request.headers.get("X-Hub-Signature-256", ""),
|
|
127
|
+
):
|
|
128
|
+
return "invalid signature", 401
|
|
129
|
+
|
|
130
|
+
data = request.get_json(silent=True) or {}
|
|
131
|
+
return jsonify({"ok": True, "received": bool(data)}), 200
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Rodar testes
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pytest
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## CI e publicacao
|
|
141
|
+
|
|
142
|
+
- CI: `.github/workflows/ci.yml`
|
|
143
|
+
- Criacao de tag/release: `.github/workflows/release.yml`
|
|
144
|
+
- Publicacao PyPI: `.github/workflows/publish.yml`
|
|
145
|
+
|
|
146
|
+
Fluxo recomendado:
|
|
147
|
+
|
|
148
|
+
1. Execute o workflow `Create Release` e informe a tag (ex: `v0.2.0`).
|
|
149
|
+
2. O release publicado dispara `Publish to PyPI`.
|
|
150
|
+
3. Configure Trusted Publisher no PyPI para este repositorio (OIDC), sem token manual.
|
|
151
|
+
|
|
152
|
+
Opcional: se preferir token, adapte o workflow para usar `PYPI_API_TOKEN`.
|
|
153
|
+
|
|
154
|
+
## Licenca
|
|
155
|
+
|
|
156
|
+
MIT
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69.5.1", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "whatsapp-cloud-api-client"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Biblioteca Python para integração com a API Oficial do WhatsApp (Cloud API)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Seu Nome" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["whatsapp", "whatsapp cloud api", "meta", "messaging", "python"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"httpx>=0.27.0,<1.0.0",
|
|
29
|
+
"pydantic>=2.7.0,<3.0.0",
|
|
30
|
+
"eval-type-backport>=0.2.0; python_version < '3.10'",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/seu-usuario/whatsapp-cloud-api-client"
|
|
35
|
+
Documentation = "https://github.com/seu-usuario/whatsapp-cloud-api-client#readme"
|
|
36
|
+
Issues = "https://github.com/seu-usuario/whatsapp-cloud-api-client/issues"
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=8.2.0,<9.0.0",
|
|
41
|
+
"pytest-asyncio>=0.23.7,<1.0.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools]
|
|
45
|
+
package-dir = {"" = "src"}
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
where = ["src"]
|
|
49
|
+
|
|
50
|
+
[tool.pytest.ini_options]
|
|
51
|
+
testpaths = ["tests"]
|
|
52
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .client import AsyncWhatsAppClient, WhatsAppClient
|
|
2
|
+
from .exceptions import WhatsAppAPIError
|
|
3
|
+
from .models import (
|
|
4
|
+
MarkAsReadResponse,
|
|
5
|
+
MediaInfoResponse,
|
|
6
|
+
MediaUploadResponse,
|
|
7
|
+
SendMessageResponse,
|
|
8
|
+
)
|
|
9
|
+
from .webhook import verify_webhook_challenge, verify_webhook_signature
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"AsyncWhatsAppClient",
|
|
13
|
+
"WhatsAppClient",
|
|
14
|
+
"WhatsAppAPIError",
|
|
15
|
+
"SendMessageResponse",
|
|
16
|
+
"MediaUploadResponse",
|
|
17
|
+
"MediaInfoResponse",
|
|
18
|
+
"MarkAsReadResponse",
|
|
19
|
+
"verify_webhook_challenge",
|
|
20
|
+
"verify_webhook_signature",
|
|
21
|
+
]
|