waclient 0.1.3__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.
- waclient-0.1.3/LICENSE +21 -0
- waclient-0.1.3/PKG-INFO +87 -0
- waclient-0.1.3/README.md +56 -0
- waclient-0.1.3/pyproject.toml +46 -0
- waclient-0.1.3/setup.cfg +4 -0
- waclient-0.1.3/tests/test_basic.py +143 -0
- waclient-0.1.3/tests/test_client.py +0 -0
- waclient-0.1.3/tests/test_messages.py +0 -0
- waclient-0.1.3/tests/test_webhooks.py +0 -0
- waclient-0.1.3/waclient/__init__.py +22 -0
- waclient-0.1.3/waclient/client.py +283 -0
- waclient-0.1.3/waclient/exceptions.py +264 -0
- waclient-0.1.3/waclient/media.py +539 -0
- waclient-0.1.3/waclient/messages.py +244 -0
- waclient-0.1.3/waclient/templates.py +589 -0
- waclient-0.1.3/waclient/utils.py +422 -0
- waclient-0.1.3/waclient/webhooks.py +178 -0
- waclient-0.1.3/waclient.egg-info/PKG-INFO +87 -0
- waclient-0.1.3/waclient.egg-info/SOURCES.txt +20 -0
- waclient-0.1.3/waclient.egg-info/dependency_links.txt +1 -0
- waclient-0.1.3/waclient.egg-info/requires.txt +7 -0
- waclient-0.1.3/waclient.egg-info/top_level.txt +1 -0
waclient-0.1.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Surenthar S
|
|
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.
|
waclient-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: waclient
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Simplified Python SDK for WhatsApp Business Cloud API
|
|
5
|
+
Author-email: Surenthar <surentharsenthilkumar2003@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Bug Reports, https://github.com/Start-up-Kraft/waclient/issues
|
|
8
|
+
Project-URL: Source, https://github.com/Start-up-Kraft/waclient
|
|
9
|
+
Project-URL: Documentation, https://github.com/Start-up-Kraft/waclient#readme
|
|
10
|
+
Keywords: whatsapp,business,api,cloud,meta,facebook,messaging
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Communications :: Chat
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
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
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: requests>=2.25.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-cov>=2.0; extra == "dev"
|
|
28
|
+
Requires-Dist: black>=21.0; extra == "dev"
|
|
29
|
+
Requires-Dist: flake8>=3.9; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# WhatsApp Biz
|
|
33
|
+
|
|
34
|
+
**Simplified Python SDK for WhatsApp Business Cloud API**
|
|
35
|
+
|
|
36
|
+
[](https://badge.fury.io/py/waclient)
|
|
37
|
+
[](https://opensource.org/licenses/MIT)
|
|
38
|
+
[](https://pypi.org/project/waclient/)
|
|
39
|
+
|
|
40
|
+
`waclient` is a clean, easy-to-use Python wrapper for the WhatsApp Business Cloud API. It handles authentication, message composition (text, media, interactive), and media management, allowing you to build WhatsApp bots and integrations quickly.
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- **Easy Authentication**: Simple client initialization.
|
|
45
|
+
- **Rich Messaging**: Send Text, Image, Video, Audio, Document, Sticker, Location, and Contact messages.
|
|
46
|
+
- **Interactive Elements**: Support for Reply Buttons and List Messages.
|
|
47
|
+
- **Templates**: Full support for WhatsApp Template Messages.
|
|
48
|
+
- **Media Handling**: Upload and retrieve media easily.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install waclient
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from waclient import WhatsAppClient
|
|
60
|
+
|
|
61
|
+
client = WhatsAppClient(
|
|
62
|
+
phone_number_id="YOUR_PHONE_ID",
|
|
63
|
+
access_token="YOUR_ACCESS_TOKEN"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
client.messages.send_text(to="15551234567", body="Hello form WhatsApp Biz!")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Documentation
|
|
70
|
+
|
|
71
|
+
- **[User Manual](USER_MANUAL.md)**: Detailed verification of all features, code examples, and configuration.
|
|
72
|
+
- **[Developer Guide](DEVELOPER_GUIDE.md)**: Setup for contributors, running tests, and project structure.
|
|
73
|
+
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
Check the `examples/` directory for ready-to-run scripts:
|
|
77
|
+
- `examples/verify_features.py`: comprehensive tour of features.
|
|
78
|
+
- `examples/verify_delivery.py`: delivery status verification.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
83
|
+
|
|
84
|
+
## Author
|
|
85
|
+
|
|
86
|
+
**Surenthar**
|
|
87
|
+
Email: surentharsenthilkumar2003@gmail.com
|
waclient-0.1.3/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# WhatsApp Biz
|
|
2
|
+
|
|
3
|
+
**Simplified Python SDK for WhatsApp Business Cloud API**
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/py/waclient)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://pypi.org/project/waclient/)
|
|
8
|
+
|
|
9
|
+
`waclient` is a clean, easy-to-use Python wrapper for the WhatsApp Business Cloud API. It handles authentication, message composition (text, media, interactive), and media management, allowing you to build WhatsApp bots and integrations quickly.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Easy Authentication**: Simple client initialization.
|
|
14
|
+
- **Rich Messaging**: Send Text, Image, Video, Audio, Document, Sticker, Location, and Contact messages.
|
|
15
|
+
- **Interactive Elements**: Support for Reply Buttons and List Messages.
|
|
16
|
+
- **Templates**: Full support for WhatsApp Template Messages.
|
|
17
|
+
- **Media Handling**: Upload and retrieve media easily.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install waclient
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from waclient import WhatsAppClient
|
|
29
|
+
|
|
30
|
+
client = WhatsAppClient(
|
|
31
|
+
phone_number_id="YOUR_PHONE_ID",
|
|
32
|
+
access_token="YOUR_ACCESS_TOKEN"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
client.messages.send_text(to="15551234567", body="Hello form WhatsApp Biz!")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Documentation
|
|
39
|
+
|
|
40
|
+
- **[User Manual](USER_MANUAL.md)**: Detailed verification of all features, code examples, and configuration.
|
|
41
|
+
- **[Developer Guide](DEVELOPER_GUIDE.md)**: Setup for contributors, running tests, and project structure.
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
Check the `examples/` directory for ready-to-run scripts:
|
|
46
|
+
- `examples/verify_features.py`: comprehensive tour of features.
|
|
47
|
+
- `examples/verify_delivery.py`: delivery status verification.
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
52
|
+
|
|
53
|
+
## Author
|
|
54
|
+
|
|
55
|
+
**Surenthar**
|
|
56
|
+
Email: surentharsenthilkumar2003@gmail.com
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "waclient"
|
|
7
|
+
version = "0.1.3"
|
|
8
|
+
description = "Simplified Python SDK for WhatsApp Business Cloud API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Surenthar", email = "surentharsenthilkumar2003@gmail.com"},
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Topic :: Communications :: Chat",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.7",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
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
|
+
keywords = ["whatsapp", "business", "api", "cloud", "meta", "facebook", "messaging"]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"requests>=2.25.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
"Bug Reports" = "https://github.com/Start-up-Kraft/waclient/issues"
|
|
34
|
+
"Source" = "https://github.com/Start-up-Kraft/waclient"
|
|
35
|
+
"Documentation" = "https://github.com/Start-up-Kraft/waclient#readme"
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=6.0",
|
|
40
|
+
"pytest-cov>=2.0",
|
|
41
|
+
"black>=21.0",
|
|
42
|
+
"flake8>=3.9",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.setuptools]
|
|
46
|
+
packages = ["waclient"]
|
waclient-0.1.3/setup.cfg
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic tests for whatsapp-biz package
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_import():
|
|
7
|
+
"""Test if package imports correctly"""
|
|
8
|
+
try:
|
|
9
|
+
from waclient import WhatsAppClient
|
|
10
|
+
|
|
11
|
+
print("[PASS] Import successful!")
|
|
12
|
+
return True
|
|
13
|
+
except ImportError as e:
|
|
14
|
+
print(f"[FAIL] Import failed: {e}")
|
|
15
|
+
return False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_client_creation():
|
|
19
|
+
"""Test if client can be instantiated"""
|
|
20
|
+
try:
|
|
21
|
+
from waclient import WhatsAppClient
|
|
22
|
+
|
|
23
|
+
client = WhatsAppClient(
|
|
24
|
+
phone_number_id="461166093735990",
|
|
25
|
+
access_token="EAAfLlnmBVq4BO75McWDhNHgL1DW9LKmdOCmLmlQbtjZBdEZCt65ub7z35gBW9gFiRjJpZC3LZA9cSTZC5Uw9lpxz3xGSyDai1FoKZAdqtRZA2huRNHrv3ymxfUljrQZAZCMs7zGEf7vzJLktSoLsZA83BHZBt9H3M06sl5ETgz4YZC7ToCBZASwnwAUC8gxGndieOSv5Y16oxhqTWPStgseH6",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
print("[PASS] Client created successfully!")
|
|
29
|
+
print(f" Phone ID: {client.phone_number_id}")
|
|
30
|
+
print(f" Base URL: {client.base_url}")
|
|
31
|
+
return True
|
|
32
|
+
except Exception as e:
|
|
33
|
+
print(f"[FAIL] Client creation failed: {e}")
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_message_builder():
|
|
38
|
+
"""Test message builders"""
|
|
39
|
+
try:
|
|
40
|
+
from waclient.messages import MessageBuilder
|
|
41
|
+
|
|
42
|
+
builder = MessageBuilder()
|
|
43
|
+
|
|
44
|
+
# Test text message
|
|
45
|
+
msg = builder.text_message("919342585854", "Hello!")
|
|
46
|
+
assert msg["type"] == "text"
|
|
47
|
+
assert msg["text"]["body"] == "Hello!"
|
|
48
|
+
|
|
49
|
+
print("[PASS] Message builder works!")
|
|
50
|
+
return True
|
|
51
|
+
except Exception as e:
|
|
52
|
+
print(f"[FAIL] Message builder failed: {e}")
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_template_builder():
|
|
57
|
+
"""Test template builders"""
|
|
58
|
+
try:
|
|
59
|
+
from waclient.templates import TemplateBuilder
|
|
60
|
+
|
|
61
|
+
component = TemplateBuilder.body_parameters("value1", "value2")
|
|
62
|
+
assert component["type"] == "body"
|
|
63
|
+
assert len(component["parameters"]) == 2
|
|
64
|
+
|
|
65
|
+
print("[PASS] Template builder works!")
|
|
66
|
+
return True
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print(f"[FAIL] Template builder failed: {e}")
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_utils():
|
|
73
|
+
"""Test utility functions"""
|
|
74
|
+
try:
|
|
75
|
+
from waclient.utils import format_phone_number, validate_phone_number
|
|
76
|
+
|
|
77
|
+
# Test phone formatting
|
|
78
|
+
phone = format_phone_number("9342585854")
|
|
79
|
+
assert phone == "919342585854"
|
|
80
|
+
|
|
81
|
+
# Test validation
|
|
82
|
+
assert validate_phone_number("919342585854") == True
|
|
83
|
+
|
|
84
|
+
print("[PASS] Utils work!")
|
|
85
|
+
return True
|
|
86
|
+
except Exception as e:
|
|
87
|
+
print(f"[FAIL] Utils failed: {e}")
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_exceptions():
|
|
92
|
+
"""Test custom exceptions"""
|
|
93
|
+
try:
|
|
94
|
+
from waclient.exceptions import (
|
|
95
|
+
WhatsAppError,
|
|
96
|
+
AuthenticationError,
|
|
97
|
+
MessageError,
|
|
98
|
+
MediaError,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Test exception creation
|
|
102
|
+
error = WhatsAppError("Test error")
|
|
103
|
+
assert str(error) == "Test error"
|
|
104
|
+
|
|
105
|
+
print("[PASS] Exceptions work!")
|
|
106
|
+
return True
|
|
107
|
+
except Exception as e:
|
|
108
|
+
print(f"[FAIL] Exceptions test failed: {e}")
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
if __name__ == "__main__":
|
|
113
|
+
print("=" * 50)
|
|
114
|
+
print("[TEST] Testing whatsapp-biz Package")
|
|
115
|
+
print("=" * 50)
|
|
116
|
+
|
|
117
|
+
tests = [
|
|
118
|
+
test_import,
|
|
119
|
+
test_client_creation,
|
|
120
|
+
test_message_builder,
|
|
121
|
+
test_template_builder,
|
|
122
|
+
test_utils,
|
|
123
|
+
test_exceptions,
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
passed = 0
|
|
127
|
+
failed = 0
|
|
128
|
+
|
|
129
|
+
for test in tests:
|
|
130
|
+
print(f"\n[RUN] Running: {test.__name__}")
|
|
131
|
+
try:
|
|
132
|
+
if test():
|
|
133
|
+
passed += 1
|
|
134
|
+
else:
|
|
135
|
+
failed += 1
|
|
136
|
+
except Exception as e:
|
|
137
|
+
print(f"[FAIL] Test crashed: {e}")
|
|
138
|
+
failed += 1
|
|
139
|
+
|
|
140
|
+
print("\n" + "=" * 50)
|
|
141
|
+
print(f"[PASS] Passed: {passed}")
|
|
142
|
+
print(f"[FAIL] Failed: {failed}")
|
|
143
|
+
print("=" * 50)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""WhatsApp Business Cloud API - Simplified Python SDK"""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
__author__ = "Your Name"
|
|
5
|
+
|
|
6
|
+
from .client import WhatsAppClient
|
|
7
|
+
from .exceptions import (
|
|
8
|
+
WhatsAppError,
|
|
9
|
+
AuthenticationError,
|
|
10
|
+
MessageError,
|
|
11
|
+
MediaError,
|
|
12
|
+
WebhookError
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"WhatsAppClient",
|
|
17
|
+
"WhatsAppError",
|
|
18
|
+
"AuthenticationError",
|
|
19
|
+
"MessageError",
|
|
20
|
+
"MediaError",
|
|
21
|
+
"WebhookError"
|
|
22
|
+
]
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File: waclient/client.py
|
|
3
|
+
Main WhatsApp Business Cloud API Client
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
import json
|
|
8
|
+
from typing import Optional, Dict, List, Any
|
|
9
|
+
from .exceptions import WhatsAppError, AuthenticationError, MessageError
|
|
10
|
+
from .messages import MessageBuilder
|
|
11
|
+
from .media import MediaHandler
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WhatsAppClient:
|
|
15
|
+
"""
|
|
16
|
+
WhatsApp Business Cloud API Client
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
client = WhatsAppClient(
|
|
20
|
+
phone_number_id="461166093735990",
|
|
21
|
+
access_token="EAAfLlnmBVq4BO75McWDhNHgL1DW9LKmdOCmLmlQbtjZBdEZCt65ub7z35gBW9gFiRjJpZC3LZA9cSTZC5Uw9lpxz3xGSyDai1FoKZAdqtRZA2huRNHrv3ymxfUljrQZAZCMs7zGEf7vzJLktSoLsZA83BHZBt9H3M06sl5ETgz4YZC7ToCBZASwnwAUC8gxGndieOSv5Y16oxhqTWPStgseH6"
|
|
22
|
+
)
|
|
23
|
+
client.send_text("919342585854", "Hello!")
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
BASE_URL = "https://graph.facebook.com/v21.0"
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
phone_number_id: str,
|
|
31
|
+
access_token: str,
|
|
32
|
+
api_version: str = "v21.0"
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Initialize WhatsApp Client
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
phone_number_id: Your WhatsApp Business phone number ID
|
|
39
|
+
access_token: Your WhatsApp Business API access token
|
|
40
|
+
api_version: API version (default: v21.0)
|
|
41
|
+
"""
|
|
42
|
+
self.phone_number_id = phone_number_id
|
|
43
|
+
self.access_token = access_token
|
|
44
|
+
self.api_version = api_version
|
|
45
|
+
self.base_url = f"https://graph.facebook.com/{api_version}"
|
|
46
|
+
self.headers = {
|
|
47
|
+
"Authorization": f"Bearer {access_token}",
|
|
48
|
+
"Content-Type": "application/json"
|
|
49
|
+
}
|
|
50
|
+
self.message_builder = MessageBuilder()
|
|
51
|
+
self.media_handler = MediaHandler(self)
|
|
52
|
+
|
|
53
|
+
def _make_request(
|
|
54
|
+
self,
|
|
55
|
+
method: str,
|
|
56
|
+
endpoint: str,
|
|
57
|
+
data: Optional[Dict] = None,
|
|
58
|
+
params: Optional[Dict] = None
|
|
59
|
+
) -> Dict:
|
|
60
|
+
"""Make HTTP request to WhatsApp API"""
|
|
61
|
+
url = f"{self.base_url}/{self.phone_number_id}/{endpoint}"
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
response = requests.request(
|
|
65
|
+
method=method,
|
|
66
|
+
url=url,
|
|
67
|
+
headers=self.headers,
|
|
68
|
+
json=data,
|
|
69
|
+
params=params,
|
|
70
|
+
timeout=30
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
response_data = response.json()
|
|
74
|
+
|
|
75
|
+
if response.status_code >= 400:
|
|
76
|
+
error_msg = response_data.get("error", {}).get("message", "Unknown error")
|
|
77
|
+
error_code = response_data.get("error", {}).get("code", 0)
|
|
78
|
+
|
|
79
|
+
if response.status_code == 401:
|
|
80
|
+
raise AuthenticationError(f"Authentication failed: {error_msg}")
|
|
81
|
+
else:
|
|
82
|
+
raise MessageError(f"API Error ({error_code}): {error_msg}")
|
|
83
|
+
|
|
84
|
+
return response_data
|
|
85
|
+
|
|
86
|
+
except requests.exceptions.RequestException as e:
|
|
87
|
+
raise WhatsAppError(f"Request failed: {str(e)}")
|
|
88
|
+
|
|
89
|
+
def send_text(
|
|
90
|
+
self,
|
|
91
|
+
to: str,
|
|
92
|
+
message: str,
|
|
93
|
+
preview_url: bool = False
|
|
94
|
+
) -> Dict:
|
|
95
|
+
"""
|
|
96
|
+
Send a text message
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
to: Recipient phone number (with country code, no + sign)
|
|
100
|
+
message: Text message to send
|
|
101
|
+
preview_url: Enable URL preview
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
API response with message ID
|
|
105
|
+
|
|
106
|
+
Example:
|
|
107
|
+
response = client.send_text("919342585854", "Hello World!")
|
|
108
|
+
"""
|
|
109
|
+
payload = self.message_builder.text_message(to, message, preview_url)
|
|
110
|
+
return self._make_request("POST", "messages", data=payload)
|
|
111
|
+
|
|
112
|
+
def send_template(
|
|
113
|
+
self,
|
|
114
|
+
to: str,
|
|
115
|
+
template_name: str,
|
|
116
|
+
language: str = "en",
|
|
117
|
+
components: Optional[List[Dict]] = None,
|
|
118
|
+
**kwargs
|
|
119
|
+
) -> Dict:
|
|
120
|
+
"""
|
|
121
|
+
Send a template message
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
to: Recipient phone number
|
|
125
|
+
template_name: Approved template name
|
|
126
|
+
language: Template language code (default: en)
|
|
127
|
+
components: Template components (parameters, buttons, etc.)
|
|
128
|
+
**kwargs: Additional template parameters
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
API response with message ID
|
|
132
|
+
|
|
133
|
+
Example:
|
|
134
|
+
client.send_template(
|
|
135
|
+
to="919342585854",
|
|
136
|
+
template_name="order_confirmation",
|
|
137
|
+
language="en",
|
|
138
|
+
components=[{
|
|
139
|
+
"type": "body",
|
|
140
|
+
"parameters": [
|
|
141
|
+
{"type": "text", "text": "Order123"},
|
|
142
|
+
{"type": "text", "text": "₹499"}
|
|
143
|
+
]
|
|
144
|
+
}]
|
|
145
|
+
)
|
|
146
|
+
"""
|
|
147
|
+
payload = self.message_builder.template_message(
|
|
148
|
+
to, template_name, language, components
|
|
149
|
+
)
|
|
150
|
+
return self._make_request("POST", "messages", data=payload)
|
|
151
|
+
|
|
152
|
+
def send_image(
|
|
153
|
+
self,
|
|
154
|
+
to: str,
|
|
155
|
+
image_url: Optional[str] = None,
|
|
156
|
+
image_id: Optional[str] = None,
|
|
157
|
+
caption: Optional[str] = None
|
|
158
|
+
) -> Dict:
|
|
159
|
+
"""
|
|
160
|
+
Send an image message
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
to: Recipient phone number
|
|
164
|
+
image_url: Public URL of the image (or use image_id)
|
|
165
|
+
image_id: Media ID from uploaded image
|
|
166
|
+
caption: Optional image caption
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
API response with message ID
|
|
170
|
+
"""
|
|
171
|
+
payload = self.message_builder.media_message(
|
|
172
|
+
to, "image", image_url, image_id, caption
|
|
173
|
+
)
|
|
174
|
+
return self._make_request("POST", "messages", data=payload)
|
|
175
|
+
|
|
176
|
+
def send_document(
|
|
177
|
+
self,
|
|
178
|
+
to: str,
|
|
179
|
+
document_url: Optional[str] = None,
|
|
180
|
+
document_id: Optional[str] = None,
|
|
181
|
+
caption: Optional[str] = None,
|
|
182
|
+
filename: Optional[str] = None
|
|
183
|
+
) -> Dict:
|
|
184
|
+
"""Send a document (PDF, DOC, etc.)"""
|
|
185
|
+
payload = self.message_builder.media_message(
|
|
186
|
+
to, "document", document_url, document_id, caption, filename
|
|
187
|
+
)
|
|
188
|
+
return self._make_request("POST", "messages", data=payload)
|
|
189
|
+
|
|
190
|
+
def send_video(
|
|
191
|
+
self,
|
|
192
|
+
to: str,
|
|
193
|
+
video_url: Optional[str] = None,
|
|
194
|
+
video_id: Optional[str] = None,
|
|
195
|
+
caption: Optional[str] = None
|
|
196
|
+
) -> Dict:
|
|
197
|
+
"""Send a video message"""
|
|
198
|
+
payload = self.message_builder.media_message(
|
|
199
|
+
to, "video", video_url, video_id, caption
|
|
200
|
+
)
|
|
201
|
+
return self._make_request("POST", "messages", data=payload)
|
|
202
|
+
|
|
203
|
+
def send_audio(
|
|
204
|
+
self,
|
|
205
|
+
to: str,
|
|
206
|
+
audio_url: Optional[str] = None,
|
|
207
|
+
audio_id: Optional[str] = None
|
|
208
|
+
) -> Dict:
|
|
209
|
+
"""Send an audio message"""
|
|
210
|
+
payload = self.message_builder.media_message(
|
|
211
|
+
to, "audio", audio_url, audio_id
|
|
212
|
+
)
|
|
213
|
+
return self._make_request("POST", "messages", data=payload)
|
|
214
|
+
|
|
215
|
+
def send_location(
|
|
216
|
+
self,
|
|
217
|
+
to: str,
|
|
218
|
+
latitude: float,
|
|
219
|
+
longitude: float,
|
|
220
|
+
name: Optional[str] = None,
|
|
221
|
+
address: Optional[str] = None
|
|
222
|
+
) -> Dict:
|
|
223
|
+
"""Send a location message"""
|
|
224
|
+
payload = self.message_builder.location_message(
|
|
225
|
+
to, latitude, longitude, name, address
|
|
226
|
+
)
|
|
227
|
+
return self._make_request("POST", "messages", data=payload)
|
|
228
|
+
|
|
229
|
+
def send_contacts(
|
|
230
|
+
self,
|
|
231
|
+
to: str,
|
|
232
|
+
contacts: List[Dict]
|
|
233
|
+
) -> Dict:
|
|
234
|
+
"""Send contact card(s)"""
|
|
235
|
+
payload = self.message_builder.contacts_message(to, contacts)
|
|
236
|
+
return self._make_request("POST", "messages", data=payload)
|
|
237
|
+
|
|
238
|
+
def send_interactive(
|
|
239
|
+
self,
|
|
240
|
+
to: str,
|
|
241
|
+
interactive_type: str,
|
|
242
|
+
body_text: str,
|
|
243
|
+
**kwargs
|
|
244
|
+
) -> Dict:
|
|
245
|
+
"""
|
|
246
|
+
Send interactive message (buttons, lists)
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
to: Recipient phone number
|
|
250
|
+
interactive_type: 'button' or 'list'
|
|
251
|
+
body_text: Message body text
|
|
252
|
+
**kwargs: Additional parameters (buttons, sections, etc.)
|
|
253
|
+
"""
|
|
254
|
+
payload = self.message_builder.interactive_message(
|
|
255
|
+
to, interactive_type, body_text, **kwargs
|
|
256
|
+
)
|
|
257
|
+
return self._make_request("POST", "messages", data=payload)
|
|
258
|
+
|
|
259
|
+
def mark_as_read(self, message_id: str) -> Dict:
|
|
260
|
+
"""Mark a message as read"""
|
|
261
|
+
payload = {
|
|
262
|
+
"messaging_product": "whatsapp",
|
|
263
|
+
"status": "read",
|
|
264
|
+
"message_id": message_id
|
|
265
|
+
}
|
|
266
|
+
return self._make_request("POST", "messages", data=payload)
|
|
267
|
+
|
|
268
|
+
def upload_media(self, file_path: str, mime_type: str) -> str:
|
|
269
|
+
"""
|
|
270
|
+
Upload media file and get media ID
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
file_path: Path to the media file
|
|
274
|
+
mime_type: MIME type (e.g., 'image/jpeg', 'application/pdf')
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
Media ID to use in send methods
|
|
278
|
+
"""
|
|
279
|
+
return self.media_handler.upload(file_path, mime_type)
|
|
280
|
+
|
|
281
|
+
def get_media_url(self, media_id: str) -> str:
|
|
282
|
+
"""Get download URL for a media ID"""
|
|
283
|
+
return self.media_handler.get_url(media_id)
|