wazzapi 0.3.0__tar.gz → 0.5.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.
- {wazzapi-0.3.0 → wazzapi-0.5.0}/PKG-INFO +2 -2
- {wazzapi-0.3.0 → wazzapi-0.5.0}/pyproject.toml +4 -4
- {wazzapi-0.3.0 → wazzapi-0.5.0}/tests/smoke_test.py +1 -1
- {wazzapi-0.3.0 → wazzapi-0.5.0}/tests/test_resources.py +67 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/__init__.py +1 -1
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/client.py +44 -1
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/__init__.py +9 -0
- wazzapi-0.5.0/wazzapi/models/campaigns.py +103 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/contacts.py +23 -0
- wazzapi-0.5.0/wazzapi/models/conversations.py +80 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/messages.py +3 -0
- wazzapi-0.5.0/wazzapi/models/webhook_subscriptions.py +87 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/resources/__init__.py +6 -0
- wazzapi-0.5.0/wazzapi/resources/campaigns.py +87 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/resources/contacts.py +36 -0
- wazzapi-0.5.0/wazzapi/resources/conversations.py +80 -0
- wazzapi-0.5.0/wazzapi/resources/devices.py +99 -0
- wazzapi-0.5.0/wazzapi/resources/webhook_subscriptions.py +80 -0
- wazzapi-0.3.0/wazzapi/resources/devices.py +0 -40
- {wazzapi-0.3.0 → wazzapi-0.5.0}/.gitignore +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/README.md +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/examples/create_template.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/examples/list_contacts.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/examples/list_devices.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/examples/preview_template.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/examples/send_message.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/examples/verify_webhook.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/tests/test_client.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/tests/test_groups.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/tests/test_media.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/tests/test_webhooks.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/errors.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/media.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/base.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/devices.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/groups.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/media.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/templates.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/models/webhooks.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/py.typed +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/resources/base.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/resources/groups.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/resources/messages.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/resources/templates.py +0 -0
- {wazzapi-0.3.0 → wazzapi-0.5.0}/wazzapi/webhooks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wazzapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Typed Python SDK for WazzAPI
|
|
5
5
|
Project-URL: API, https://api.wazzapi.com
|
|
6
6
|
Project-URL: Homepage, https://github.com/wazzapihq/wazzapi-py
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
|
-
Requires-Dist: cryptography<
|
|
20
|
+
Requires-Dist: cryptography<50.0,>=46.0
|
|
21
21
|
Requires-Dist: httpx<1.0,>=0.28
|
|
22
22
|
Requires-Dist: pydantic<3.0,>=2.11
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "wazzapi"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "Typed Python SDK for WazzAPI"
|
|
5
5
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -19,7 +19,7 @@ classifiers = [
|
|
|
19
19
|
"Typing :: Typed",
|
|
20
20
|
]
|
|
21
21
|
dependencies = [
|
|
22
|
-
"cryptography>=
|
|
22
|
+
"cryptography>=46.0,<50.0",
|
|
23
23
|
"httpx>=0.28,<1.0",
|
|
24
24
|
"pydantic>=2.11,<3.0",
|
|
25
25
|
]
|
|
@@ -30,8 +30,8 @@ Homepage = "https://github.com/wazzapihq/wazzapi-py"
|
|
|
30
30
|
|
|
31
31
|
[dependency-groups]
|
|
32
32
|
dev = [
|
|
33
|
-
"pytest>=
|
|
34
|
-
"pytest-asyncio>=0
|
|
33
|
+
"pytest>=9.0,<10.0",
|
|
34
|
+
"pytest-asyncio>=1.0,<2.0",
|
|
35
35
|
"twine>=6.1,<7.0",
|
|
36
36
|
]
|
|
37
37
|
|
|
@@ -213,3 +213,70 @@ def test_sync_status_returns_typed_list() -> None:
|
|
|
213
213
|
assert len(result) == 1
|
|
214
214
|
assert isinstance(result[0], models.ContactSyncStatusResponse)
|
|
215
215
|
assert result[0].account_id == "wa_123"
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_get_profile_picture_returns_metadata() -> None:
|
|
219
|
+
seen: dict[str, object] = {}
|
|
220
|
+
|
|
221
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
222
|
+
seen["method"] = request.method
|
|
223
|
+
seen["path"] = request.url.path
|
|
224
|
+
seen["query"] = dict(request.url.params)
|
|
225
|
+
return httpx.Response(
|
|
226
|
+
200,
|
|
227
|
+
json={
|
|
228
|
+
"contact_id": "contact_1",
|
|
229
|
+
"phone_number": "+6281234567890",
|
|
230
|
+
"url": "https://cdn.example.com/pic.jpg",
|
|
231
|
+
"picture_id": "pic_1",
|
|
232
|
+
"picture_type": "image",
|
|
233
|
+
"preview": True,
|
|
234
|
+
"whatsapp_account_id": "wa_1",
|
|
235
|
+
"cached": False,
|
|
236
|
+
},
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
transport = httpx.MockTransport(handler)
|
|
240
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
241
|
+
result = client.contacts.get_profile_picture(
|
|
242
|
+
"contact_1",
|
|
243
|
+
whatsapp_account_id="wa_1",
|
|
244
|
+
preview=True,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
assert seen["method"] == "GET"
|
|
248
|
+
assert seen["path"] == "/api/v1/contacts/contact_1/profile-picture"
|
|
249
|
+
assert seen["query"] == {"whatsapp_account_id": "wa_1", "preview": "true"}
|
|
250
|
+
assert isinstance(result, models.ContactProfilePictureResponse)
|
|
251
|
+
assert result.url == "https://cdn.example.com/pic.jpg"
|
|
252
|
+
assert result.preview is True
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def test_get_profile_picture_image_returns_bytes() -> None:
|
|
256
|
+
seen: dict[str, object] = {}
|
|
257
|
+
image_bytes = b"\xff\xd8\xff\xe0fake-jpeg"
|
|
258
|
+
|
|
259
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
260
|
+
seen["method"] = request.method
|
|
261
|
+
seen["path"] = request.url.path
|
|
262
|
+
seen["query"] = dict(request.url.params)
|
|
263
|
+
return httpx.Response(
|
|
264
|
+
200,
|
|
265
|
+
content=image_bytes,
|
|
266
|
+
headers={"content-type": "image/jpeg"},
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
transport = httpx.MockTransport(handler)
|
|
270
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
271
|
+
result = client.contacts.get_profile_picture_image(
|
|
272
|
+
"contact_1",
|
|
273
|
+
proxy=True,
|
|
274
|
+
preview=False,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
assert seen["method"] == "GET"
|
|
278
|
+
assert seen["path"] == "/api/v1/contacts/contact_1/profile-picture/image"
|
|
279
|
+
assert seen["query"] == {"proxy": "true", "preview": "false"}
|
|
280
|
+
assert isinstance(result, models.ContactProfilePictureImageResult)
|
|
281
|
+
assert result.content == image_bytes
|
|
282
|
+
assert result.content_type == "image/jpeg"
|
|
@@ -7,7 +7,16 @@ import httpx
|
|
|
7
7
|
from pydantic import BaseModel, TypeAdapter
|
|
8
8
|
|
|
9
9
|
from .errors import WazzapiAPIError
|
|
10
|
-
from .resources import
|
|
10
|
+
from .resources import (
|
|
11
|
+
CampaignsResource,
|
|
12
|
+
ContactsResource,
|
|
13
|
+
ConversationsResource,
|
|
14
|
+
DevicesResource,
|
|
15
|
+
GroupsResource,
|
|
16
|
+
MessagesResource,
|
|
17
|
+
TemplatesResource,
|
|
18
|
+
WebhookSubscriptionsResource,
|
|
19
|
+
)
|
|
11
20
|
|
|
12
21
|
DEFAULT_BASE_URL = "https://api.wazzapi.com"
|
|
13
22
|
|
|
@@ -38,11 +47,14 @@ class WazzapiClient:
|
|
|
38
47
|
transport=transport,
|
|
39
48
|
)
|
|
40
49
|
|
|
50
|
+
self.campaigns = CampaignsResource(self)
|
|
41
51
|
self.contacts = ContactsResource(self)
|
|
52
|
+
self.conversations = ConversationsResource(self)
|
|
42
53
|
self.devices = DevicesResource(self)
|
|
43
54
|
self.groups = GroupsResource(self)
|
|
44
55
|
self.messages = MessagesResource(self)
|
|
45
56
|
self.templates = TemplatesResource(self)
|
|
57
|
+
self.webhook_subscriptions = WebhookSubscriptionsResource(self)
|
|
46
58
|
|
|
47
59
|
@staticmethod
|
|
48
60
|
def _build_headers(
|
|
@@ -107,6 +119,37 @@ class WazzapiClient:
|
|
|
107
119
|
payload = response.json()
|
|
108
120
|
return TypeAdapter(response_model).validate_python(payload)
|
|
109
121
|
|
|
122
|
+
def _request_bytes(
|
|
123
|
+
self,
|
|
124
|
+
method: str,
|
|
125
|
+
path: str,
|
|
126
|
+
*,
|
|
127
|
+
params: Mapping[str, Any] | None = None,
|
|
128
|
+
response_model: Any | None = None,
|
|
129
|
+
) -> Any:
|
|
130
|
+
"""Issue a request and return binary content (follows redirects)."""
|
|
131
|
+
|
|
132
|
+
response = self._client.request(
|
|
133
|
+
method,
|
|
134
|
+
path,
|
|
135
|
+
params=self._filter_none(params),
|
|
136
|
+
follow_redirects=True,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
if response.status_code >= 400:
|
|
140
|
+
raise WazzapiAPIError.from_response(response)
|
|
141
|
+
|
|
142
|
+
payload = {
|
|
143
|
+
"content": response.content,
|
|
144
|
+
"content_type": response.headers.get("content-type"),
|
|
145
|
+
"final_url": str(response.url) if response.url else None,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if response_model is None:
|
|
149
|
+
return payload
|
|
150
|
+
|
|
151
|
+
return TypeAdapter(response_model).validate_python(payload)
|
|
152
|
+
|
|
110
153
|
@staticmethod
|
|
111
154
|
def _filter_none(data: Mapping[str, Any] | None) -> dict[str, Any] | None:
|
|
112
155
|
if data is None:
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
from .base import WazzapiModel
|
|
2
|
+
from .campaigns import *
|
|
3
|
+
from .campaigns import __all__ as campaigns_all
|
|
2
4
|
from .contacts import *
|
|
3
5
|
from .contacts import __all__ as contacts_all
|
|
6
|
+
from .conversations import *
|
|
7
|
+
from .conversations import __all__ as conversations_all
|
|
4
8
|
from .devices import *
|
|
5
9
|
from .devices import __all__ as devices_all
|
|
6
10
|
from .groups import *
|
|
@@ -11,16 +15,21 @@ from .messages import *
|
|
|
11
15
|
from .messages import __all__ as messages_all
|
|
12
16
|
from .templates import *
|
|
13
17
|
from .templates import __all__ as templates_all
|
|
18
|
+
from .webhook_subscriptions import *
|
|
19
|
+
from .webhook_subscriptions import __all__ as webhook_subscriptions_all
|
|
14
20
|
from .webhooks import *
|
|
15
21
|
from .webhooks import __all__ as webhooks_all
|
|
16
22
|
|
|
17
23
|
__all__ = [
|
|
18
24
|
"WazzapiModel",
|
|
25
|
+
*campaigns_all,
|
|
19
26
|
*contacts_all,
|
|
27
|
+
*conversations_all,
|
|
20
28
|
*devices_all,
|
|
21
29
|
*groups_all,
|
|
22
30
|
*media_all,
|
|
23
31
|
*messages_all,
|
|
24
32
|
*templates_all,
|
|
33
|
+
*webhook_subscriptions_all,
|
|
25
34
|
*webhooks_all,
|
|
26
35
|
]
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .base import WazzapiModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CampaignCreateRequest(WazzapiModel):
|
|
10
|
+
name: str
|
|
11
|
+
whatsapp_account_id: str
|
|
12
|
+
recipient_type: str
|
|
13
|
+
description: str | None = None
|
|
14
|
+
template_id: str | None = None
|
|
15
|
+
message_type: str = "text"
|
|
16
|
+
custom_message: str | None = None
|
|
17
|
+
message_payload: dict[str, Any] | None = None
|
|
18
|
+
recipient_group_ids: list[str] | None = None
|
|
19
|
+
recipient_contact_ids: list[str] | None = None
|
|
20
|
+
scheduled_for: datetime | None = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CampaignUpdateRequest(WazzapiModel):
|
|
24
|
+
name: str | None = None
|
|
25
|
+
description: str | None = None
|
|
26
|
+
template_id: str | None = None
|
|
27
|
+
message_type: str | None = None
|
|
28
|
+
custom_message: str | None = None
|
|
29
|
+
message_payload: dict[str, Any] | None = None
|
|
30
|
+
recipient_type: str | None = None
|
|
31
|
+
recipient_group_ids: list[str] | None = None
|
|
32
|
+
recipient_contact_ids: list[str] | None = None
|
|
33
|
+
scheduled_for: datetime | None = None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class CampaignItem(WazzapiModel):
|
|
37
|
+
id: str
|
|
38
|
+
name: str
|
|
39
|
+
status: str
|
|
40
|
+
recipient_type: str
|
|
41
|
+
total_recipients: int
|
|
42
|
+
messages_sent: int
|
|
43
|
+
messages_delivered: int
|
|
44
|
+
messages_failed: int
|
|
45
|
+
whatsapp_account_id: str
|
|
46
|
+
message_type: str = "text"
|
|
47
|
+
recipient_contact_ids: list[str] | None = None
|
|
48
|
+
scheduled_for: str | None = None
|
|
49
|
+
created_at: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class CampaignListResponse(WazzapiModel):
|
|
53
|
+
items: list[CampaignItem]
|
|
54
|
+
total: int
|
|
55
|
+
limit: int
|
|
56
|
+
offset: int
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class CampaignResponse(WazzapiModel):
|
|
60
|
+
id: str
|
|
61
|
+
name: str
|
|
62
|
+
status: str
|
|
63
|
+
description: str | None = None
|
|
64
|
+
whatsapp_account_id: str
|
|
65
|
+
template_id: str | None = None
|
|
66
|
+
message_type: str = "text"
|
|
67
|
+
custom_message: str | None = None
|
|
68
|
+
message_payload: dict[str, Any] | None = None
|
|
69
|
+
recipient_type: str
|
|
70
|
+
recipient_group_ids: list[str] | None = None
|
|
71
|
+
recipient_contact_ids: list[str] | None = None
|
|
72
|
+
total_recipients: int = 0
|
|
73
|
+
messages_sent: int = 0
|
|
74
|
+
messages_delivered: int = 0
|
|
75
|
+
messages_failed: int = 0
|
|
76
|
+
scheduled_for: str | None = None
|
|
77
|
+
created_at: str | None = None
|
|
78
|
+
updated_at: str | None = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class CampaignActionResponse(WazzapiModel):
|
|
82
|
+
success: bool
|
|
83
|
+
campaign_id: str
|
|
84
|
+
status: str
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class CampaignExecuteResponse(WazzapiModel):
|
|
88
|
+
success: bool
|
|
89
|
+
campaign_id: str
|
|
90
|
+
status: str
|
|
91
|
+
total_recipients: int
|
|
92
|
+
job_id: str | None = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
__all__ = [
|
|
96
|
+
"CampaignActionResponse",
|
|
97
|
+
"CampaignCreateRequest",
|
|
98
|
+
"CampaignExecuteResponse",
|
|
99
|
+
"CampaignItem",
|
|
100
|
+
"CampaignListResponse",
|
|
101
|
+
"CampaignResponse",
|
|
102
|
+
"CampaignUpdateRequest",
|
|
103
|
+
]
|
|
@@ -173,6 +173,27 @@ class ContactUpdateRequest(WazzapiModel):
|
|
|
173
173
|
is_opted_out: bool | None = None
|
|
174
174
|
|
|
175
175
|
|
|
176
|
+
class ContactProfilePictureResponse(WazzapiModel):
|
|
177
|
+
"""Ephemeral WhatsApp profile picture metadata for a contact."""
|
|
178
|
+
|
|
179
|
+
contact_id: str
|
|
180
|
+
phone_number: str
|
|
181
|
+
url: str
|
|
182
|
+
picture_id: str | None = None
|
|
183
|
+
picture_type: str | None = None
|
|
184
|
+
preview: bool
|
|
185
|
+
whatsapp_account_id: str
|
|
186
|
+
cached: bool = False
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class ContactProfilePictureImageResult(WazzapiModel):
|
|
190
|
+
"""Raw image bytes returned by the profile-picture image endpoint."""
|
|
191
|
+
|
|
192
|
+
content: bytes
|
|
193
|
+
content_type: str | None = None
|
|
194
|
+
final_url: str | None = None
|
|
195
|
+
|
|
196
|
+
|
|
176
197
|
class RemoveFromGroupRequest(WazzapiModel):
|
|
177
198
|
contact_ids: list[str]
|
|
178
199
|
|
|
@@ -193,6 +214,8 @@ __all__ = [
|
|
|
193
214
|
"ContactGroupUpdateRequest",
|
|
194
215
|
"ContactItem",
|
|
195
216
|
"ContactListResponse",
|
|
217
|
+
"ContactProfilePictureImageResult",
|
|
218
|
+
"ContactProfilePictureResponse",
|
|
196
219
|
"ContactResponse",
|
|
197
220
|
"ContactSyncHistoryItem",
|
|
198
221
|
"ContactSyncHistoryResponse",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from .base import WazzapiModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ConversationItem(WazzapiModel):
|
|
9
|
+
id: str
|
|
10
|
+
whatsapp_account_id: str
|
|
11
|
+
contact_id: str | None = None
|
|
12
|
+
phone_number: str
|
|
13
|
+
status: str
|
|
14
|
+
assignee_user_id: str | None = None
|
|
15
|
+
subject: str | None = None
|
|
16
|
+
last_message_preview: str | None = None
|
|
17
|
+
last_message_at: datetime | None = None
|
|
18
|
+
last_inbound_at: datetime | None = None
|
|
19
|
+
last_outbound_at: datetime | None = None
|
|
20
|
+
unread_count: int
|
|
21
|
+
created_at: datetime
|
|
22
|
+
updated_at: datetime
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ConversationListResponse(WazzapiModel):
|
|
26
|
+
conversations: list[ConversationItem]
|
|
27
|
+
total: int
|
|
28
|
+
limit: int
|
|
29
|
+
offset: int
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ConversationUpdateRequest(WazzapiModel):
|
|
33
|
+
status: str | None = None
|
|
34
|
+
assignee_user_id: str | None = None
|
|
35
|
+
clear_assignee: bool = False
|
|
36
|
+
mark_read: bool = False
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ConversationMessageItem(WazzapiModel):
|
|
40
|
+
id: str
|
|
41
|
+
direction: str
|
|
42
|
+
content: str
|
|
43
|
+
status: str
|
|
44
|
+
message_type: str
|
|
45
|
+
phone_number: str
|
|
46
|
+
whatsapp_message_id: str | None = None
|
|
47
|
+
created_at: datetime
|
|
48
|
+
sent_at: datetime | None = None
|
|
49
|
+
delivered_at: datetime | None = None
|
|
50
|
+
read_at: datetime | None = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ConversationMessageListResponse(WazzapiModel):
|
|
54
|
+
messages: list[ConversationMessageItem]
|
|
55
|
+
total: int
|
|
56
|
+
limit: int
|
|
57
|
+
offset: int
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ConversationReplyRequest(WazzapiModel):
|
|
61
|
+
content: str
|
|
62
|
+
whatsapp_account_id: str | None = None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class ConversationReplyResponse(WazzapiModel):
|
|
66
|
+
success: bool
|
|
67
|
+
message_id: str
|
|
68
|
+
conversation_id: str
|
|
69
|
+
status: str
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
"ConversationItem",
|
|
74
|
+
"ConversationListResponse",
|
|
75
|
+
"ConversationMessageItem",
|
|
76
|
+
"ConversationMessageListResponse",
|
|
77
|
+
"ConversationReplyRequest",
|
|
78
|
+
"ConversationReplyResponse",
|
|
79
|
+
"ConversationUpdateRequest",
|
|
80
|
+
]
|
|
@@ -136,6 +136,9 @@ class SendMessageRequest(WazzapiModel):
|
|
|
136
136
|
message_type: str = "text"
|
|
137
137
|
media_type: str | None = None
|
|
138
138
|
media_url: str | None = None
|
|
139
|
+
media_base64: str | None = None
|
|
140
|
+
filename: str | None = None
|
|
141
|
+
mimetype: str | None = None
|
|
139
142
|
caption: str | None = None
|
|
140
143
|
latitude: float | None = None
|
|
141
144
|
longitude: float | None = None
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from .base import WazzapiModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class WebhookCreateRequest(WazzapiModel):
|
|
9
|
+
url: str
|
|
10
|
+
subscribed_events: list[str]
|
|
11
|
+
secret: str | None = None
|
|
12
|
+
description: str | None = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WebhookUpdateRequest(WazzapiModel):
|
|
16
|
+
url: str | None = None
|
|
17
|
+
subscribed_events: list[str] | None = None
|
|
18
|
+
is_active: bool | None = None
|
|
19
|
+
description: str | None = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class WebhookResponse(WazzapiModel):
|
|
23
|
+
id: str
|
|
24
|
+
url: str
|
|
25
|
+
secret_prefix: str
|
|
26
|
+
subscribed_events: list[str]
|
|
27
|
+
is_active: bool
|
|
28
|
+
status: str
|
|
29
|
+
failure_count: int
|
|
30
|
+
last_success_at: datetime | None = None
|
|
31
|
+
last_failure_at: datetime | None = None
|
|
32
|
+
description: str | None = None
|
|
33
|
+
created_at: datetime
|
|
34
|
+
updated_at: datetime
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class WebhookListItem(WazzapiModel):
|
|
38
|
+
id: str
|
|
39
|
+
url: str
|
|
40
|
+
subscribed_events: list[str]
|
|
41
|
+
is_active: bool
|
|
42
|
+
status: str
|
|
43
|
+
failure_count: int
|
|
44
|
+
last_success_at: datetime | None = None
|
|
45
|
+
last_failure_at: datetime | None = None
|
|
46
|
+
description: str | None = None
|
|
47
|
+
created_at: datetime
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class WebhookListResponse(WazzapiModel):
|
|
51
|
+
webhooks: list[WebhookListItem]
|
|
52
|
+
total: int
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class WebhookEventListItem(WazzapiModel):
|
|
56
|
+
id: str
|
|
57
|
+
event_type: str
|
|
58
|
+
status: str
|
|
59
|
+
retry_count: int
|
|
60
|
+
response_code: int | None = None
|
|
61
|
+
error_message: str | None = None
|
|
62
|
+
created_at: datetime
|
|
63
|
+
delivered_at: datetime | None = None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class WebhookEventListResponse(WazzapiModel):
|
|
67
|
+
events: list[WebhookEventListItem]
|
|
68
|
+
total: int
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class PingWebhookResponse(WazzapiModel):
|
|
72
|
+
success: bool
|
|
73
|
+
status_code: int | None = None
|
|
74
|
+
response_time_ms: int | None = None
|
|
75
|
+
error: str | None = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
__all__ = [
|
|
79
|
+
"PingWebhookResponse",
|
|
80
|
+
"WebhookCreateRequest",
|
|
81
|
+
"WebhookEventListItem",
|
|
82
|
+
"WebhookEventListResponse",
|
|
83
|
+
"WebhookListItem",
|
|
84
|
+
"WebhookListResponse",
|
|
85
|
+
"WebhookResponse",
|
|
86
|
+
"WebhookUpdateRequest",
|
|
87
|
+
]
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
from .campaigns import CampaignsResource
|
|
1
2
|
from .contacts import ContactsResource
|
|
3
|
+
from .conversations import ConversationsResource
|
|
2
4
|
from .devices import DevicesResource
|
|
3
5
|
from .groups import GroupsResource
|
|
4
6
|
from .messages import MessagesResource
|
|
5
7
|
from .templates import TemplatesResource
|
|
8
|
+
from .webhook_subscriptions import WebhookSubscriptionsResource
|
|
6
9
|
|
|
7
10
|
__all__ = [
|
|
11
|
+
"CampaignsResource",
|
|
8
12
|
"ContactsResource",
|
|
13
|
+
"ConversationsResource",
|
|
9
14
|
"DevicesResource",
|
|
10
15
|
"GroupsResource",
|
|
11
16
|
"MessagesResource",
|
|
12
17
|
"TemplatesResource",
|
|
18
|
+
"WebhookSubscriptionsResource",
|
|
13
19
|
]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .. import models
|
|
6
|
+
from .base import BaseResource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CampaignsResource(BaseResource):
|
|
10
|
+
def list(
|
|
11
|
+
self,
|
|
12
|
+
*,
|
|
13
|
+
limit: int | None = None,
|
|
14
|
+
offset: int | None = None,
|
|
15
|
+
status: str | None = None,
|
|
16
|
+
) -> models.CampaignListResponse:
|
|
17
|
+
return self._client._request(
|
|
18
|
+
"GET",
|
|
19
|
+
"/api/v1/campaigns",
|
|
20
|
+
params={"limit": limit, "offset": offset, "status": status},
|
|
21
|
+
response_model=models.CampaignListResponse,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def create(
|
|
25
|
+
self,
|
|
26
|
+
payload: models.CampaignCreateRequest | dict[str, Any],
|
|
27
|
+
) -> models.CampaignResponse:
|
|
28
|
+
return self._client._request(
|
|
29
|
+
"POST",
|
|
30
|
+
"/api/v1/campaigns",
|
|
31
|
+
json_body=payload,
|
|
32
|
+
response_model=models.CampaignResponse,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def get(self, campaign_id: str) -> models.CampaignResponse:
|
|
36
|
+
return self._client._request(
|
|
37
|
+
"GET",
|
|
38
|
+
f"/api/v1/campaigns/{campaign_id}",
|
|
39
|
+
response_model=models.CampaignResponse,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def update(
|
|
43
|
+
self,
|
|
44
|
+
campaign_id: str,
|
|
45
|
+
payload: models.CampaignUpdateRequest | dict[str, Any],
|
|
46
|
+
) -> models.CampaignResponse:
|
|
47
|
+
return self._client._request(
|
|
48
|
+
"PATCH",
|
|
49
|
+
f"/api/v1/campaigns/{campaign_id}",
|
|
50
|
+
json_body=payload,
|
|
51
|
+
response_model=models.CampaignResponse,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def delete(self, campaign_id: str) -> None:
|
|
55
|
+
self._client._request("DELETE", f"/api/v1/campaigns/{campaign_id}")
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
def execute(self, campaign_id: str) -> models.CampaignExecuteResponse:
|
|
59
|
+
return self._client._request(
|
|
60
|
+
"POST",
|
|
61
|
+
f"/api/v1/campaigns/{campaign_id}/execute",
|
|
62
|
+
response_model=models.CampaignExecuteResponse,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def pause(self, campaign_id: str) -> models.CampaignActionResponse:
|
|
66
|
+
return self._client._request(
|
|
67
|
+
"POST",
|
|
68
|
+
f"/api/v1/campaigns/{campaign_id}/pause",
|
|
69
|
+
response_model=models.CampaignActionResponse,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def resume(self, campaign_id: str) -> models.CampaignActionResponse:
|
|
73
|
+
return self._client._request(
|
|
74
|
+
"POST",
|
|
75
|
+
f"/api/v1/campaigns/{campaign_id}/resume",
|
|
76
|
+
response_model=models.CampaignActionResponse,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def cancel(self, campaign_id: str) -> models.CampaignActionResponse:
|
|
80
|
+
return self._client._request(
|
|
81
|
+
"POST",
|
|
82
|
+
f"/api/v1/campaigns/{campaign_id}/cancel",
|
|
83
|
+
response_model=models.CampaignActionResponse,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
__all__ = ["CampaignsResource"]
|
|
@@ -218,5 +218,41 @@ class ContactsResource(BaseResource):
|
|
|
218
218
|
self._client._request("DELETE", f"/api/v1/contacts/{contact_id}")
|
|
219
219
|
return None
|
|
220
220
|
|
|
221
|
+
def get_profile_picture(
|
|
222
|
+
self,
|
|
223
|
+
contact_id: str,
|
|
224
|
+
*,
|
|
225
|
+
whatsapp_account_id: str | None = None,
|
|
226
|
+
preview: bool | None = None,
|
|
227
|
+
) -> models.ContactProfilePictureResponse:
|
|
228
|
+
return self._client._request(
|
|
229
|
+
"GET",
|
|
230
|
+
f"/api/v1/contacts/{contact_id}/profile-picture",
|
|
231
|
+
params={
|
|
232
|
+
"whatsapp_account_id": whatsapp_account_id,
|
|
233
|
+
"preview": preview,
|
|
234
|
+
},
|
|
235
|
+
response_model=models.ContactProfilePictureResponse,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
def get_profile_picture_image(
|
|
239
|
+
self,
|
|
240
|
+
contact_id: str,
|
|
241
|
+
*,
|
|
242
|
+
whatsapp_account_id: str | None = None,
|
|
243
|
+
preview: bool | None = None,
|
|
244
|
+
proxy: bool | None = None,
|
|
245
|
+
) -> models.ContactProfilePictureImageResult:
|
|
246
|
+
return self._client._request_bytes(
|
|
247
|
+
"GET",
|
|
248
|
+
f"/api/v1/contacts/{contact_id}/profile-picture/image",
|
|
249
|
+
params={
|
|
250
|
+
"whatsapp_account_id": whatsapp_account_id,
|
|
251
|
+
"preview": preview,
|
|
252
|
+
"proxy": proxy,
|
|
253
|
+
},
|
|
254
|
+
response_model=models.ContactProfilePictureImageResult,
|
|
255
|
+
)
|
|
256
|
+
|
|
221
257
|
|
|
222
258
|
__all__ = ["ContactsResource"]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .. import models
|
|
6
|
+
from .base import BaseResource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConversationsResource(BaseResource):
|
|
10
|
+
def list(
|
|
11
|
+
self,
|
|
12
|
+
*,
|
|
13
|
+
limit: int | None = None,
|
|
14
|
+
offset: int | None = None,
|
|
15
|
+
status: str | None = None,
|
|
16
|
+
whatsapp_account_id: str | None = None,
|
|
17
|
+
assignee_user_id: str | None = None,
|
|
18
|
+
search: str | None = None,
|
|
19
|
+
) -> models.ConversationListResponse:
|
|
20
|
+
return self._client._request(
|
|
21
|
+
"GET",
|
|
22
|
+
"/api/v1/conversations",
|
|
23
|
+
params={
|
|
24
|
+
"limit": limit,
|
|
25
|
+
"offset": offset,
|
|
26
|
+
"status": status,
|
|
27
|
+
"whatsapp_account_id": whatsapp_account_id,
|
|
28
|
+
"assignee_user_id": assignee_user_id,
|
|
29
|
+
"search": search,
|
|
30
|
+
},
|
|
31
|
+
response_model=models.ConversationListResponse,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def get(self, conversation_id: str) -> models.ConversationItem:
|
|
35
|
+
return self._client._request(
|
|
36
|
+
"GET",
|
|
37
|
+
f"/api/v1/conversations/{conversation_id}",
|
|
38
|
+
response_model=models.ConversationItem,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def update(
|
|
42
|
+
self,
|
|
43
|
+
conversation_id: str,
|
|
44
|
+
payload: models.ConversationUpdateRequest | dict[str, Any],
|
|
45
|
+
) -> models.ConversationItem:
|
|
46
|
+
return self._client._request(
|
|
47
|
+
"PATCH",
|
|
48
|
+
f"/api/v1/conversations/{conversation_id}",
|
|
49
|
+
json_body=payload,
|
|
50
|
+
response_model=models.ConversationItem,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def list_messages(
|
|
54
|
+
self,
|
|
55
|
+
conversation_id: str,
|
|
56
|
+
*,
|
|
57
|
+
limit: int | None = None,
|
|
58
|
+
offset: int | None = None,
|
|
59
|
+
) -> models.ConversationMessageListResponse:
|
|
60
|
+
return self._client._request(
|
|
61
|
+
"GET",
|
|
62
|
+
f"/api/v1/conversations/{conversation_id}/messages",
|
|
63
|
+
params={"limit": limit, "offset": offset},
|
|
64
|
+
response_model=models.ConversationMessageListResponse,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def reply(
|
|
68
|
+
self,
|
|
69
|
+
conversation_id: str,
|
|
70
|
+
payload: models.ConversationReplyRequest | dict[str, Any],
|
|
71
|
+
) -> models.ConversationReplyResponse:
|
|
72
|
+
return self._client._request(
|
|
73
|
+
"POST",
|
|
74
|
+
f"/api/v1/conversations/{conversation_id}/reply",
|
|
75
|
+
json_body=payload,
|
|
76
|
+
response_model=models.ConversationReplyResponse,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
__all__ = ["ConversationsResource"]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from .. import models
|
|
4
|
+
from .base import BaseResource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DevicesResource(BaseResource):
|
|
8
|
+
def list(
|
|
9
|
+
self,
|
|
10
|
+
*,
|
|
11
|
+
limit: int | None = None,
|
|
12
|
+
offset: int | None = None,
|
|
13
|
+
status: str | None = None,
|
|
14
|
+
search: str | None = None,
|
|
15
|
+
sort_by: str | None = None,
|
|
16
|
+
sort_order: str | None = None,
|
|
17
|
+
) -> models.DeviceListResponse:
|
|
18
|
+
return self._client._request(
|
|
19
|
+
"GET",
|
|
20
|
+
"/api/v1/devices",
|
|
21
|
+
params={
|
|
22
|
+
"limit": limit,
|
|
23
|
+
"offset": offset,
|
|
24
|
+
"status": status,
|
|
25
|
+
"search": search,
|
|
26
|
+
"sort_by": sort_by,
|
|
27
|
+
"sort_order": sort_order,
|
|
28
|
+
},
|
|
29
|
+
response_model=models.DeviceListResponse,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def get(self, device_id: str) -> models.DeviceResponse:
|
|
33
|
+
return self._client._request(
|
|
34
|
+
"GET",
|
|
35
|
+
f"/api/v1/devices/{device_id}",
|
|
36
|
+
response_model=models.DeviceResponse,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def link(self, payload: dict) -> dict:
|
|
40
|
+
return self._client._request(
|
|
41
|
+
"POST",
|
|
42
|
+
"/api/v1/devices",
|
|
43
|
+
json_body=payload,
|
|
44
|
+
response_model=dict,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def get_qr(self, device_id: str) -> dict:
|
|
48
|
+
return self._client._request(
|
|
49
|
+
"GET",
|
|
50
|
+
f"/api/v1/devices/{device_id}/qr",
|
|
51
|
+
response_model=dict,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def get_status(self, device_id: str) -> dict:
|
|
55
|
+
return self._client._request(
|
|
56
|
+
"GET",
|
|
57
|
+
f"/api/v1/devices/{device_id}/status",
|
|
58
|
+
response_model=dict,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def disconnect(self, device_id: str) -> dict:
|
|
62
|
+
return self._client._request(
|
|
63
|
+
"POST",
|
|
64
|
+
f"/api/v1/devices/{device_id}/disconnect",
|
|
65
|
+
response_model=dict,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def reconnect(self, device_id: str) -> dict:
|
|
69
|
+
return self._client._request(
|
|
70
|
+
"POST",
|
|
71
|
+
f"/api/v1/devices/{device_id}/reconnect",
|
|
72
|
+
response_model=dict,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def get_proxy(self, device_id: str) -> dict:
|
|
76
|
+
return self._client._request(
|
|
77
|
+
"GET",
|
|
78
|
+
f"/api/v1/devices/{device_id}/proxy",
|
|
79
|
+
response_model=dict,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def update_proxy(self, device_id: str, payload: dict) -> dict:
|
|
83
|
+
return self._client._request(
|
|
84
|
+
"PATCH",
|
|
85
|
+
f"/api/v1/devices/{device_id}/proxy",
|
|
86
|
+
json_body=payload,
|
|
87
|
+
response_model=dict,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def test_proxy(self, payload: dict) -> dict:
|
|
91
|
+
return self._client._request(
|
|
92
|
+
"POST",
|
|
93
|
+
"/api/v1/devices/proxy/test",
|
|
94
|
+
json_body=payload,
|
|
95
|
+
response_model=dict,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = ["DevicesResource"]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .. import models
|
|
6
|
+
from .base import BaseResource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class WebhookSubscriptionsResource(BaseResource):
|
|
10
|
+
def list(
|
|
11
|
+
self,
|
|
12
|
+
*,
|
|
13
|
+
limit: int | None = None,
|
|
14
|
+
offset: int | None = None,
|
|
15
|
+
active_only: bool | None = None,
|
|
16
|
+
) -> models.WebhookListResponse:
|
|
17
|
+
return self._client._request(
|
|
18
|
+
"GET",
|
|
19
|
+
"/api/v1/webhooks/subscriptions",
|
|
20
|
+
params={"limit": limit, "offset": offset, "active_only": active_only},
|
|
21
|
+
response_model=models.WebhookListResponse,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def create(
|
|
25
|
+
self,
|
|
26
|
+
payload: models.WebhookCreateRequest | dict[str, Any],
|
|
27
|
+
) -> models.WebhookResponse:
|
|
28
|
+
return self._client._request(
|
|
29
|
+
"POST",
|
|
30
|
+
"/api/v1/webhooks/subscriptions",
|
|
31
|
+
json_body=payload,
|
|
32
|
+
response_model=models.WebhookResponse,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def get(self, webhook_id: str) -> models.WebhookResponse:
|
|
36
|
+
return self._client._request(
|
|
37
|
+
"GET",
|
|
38
|
+
f"/api/v1/webhooks/subscriptions/{webhook_id}",
|
|
39
|
+
response_model=models.WebhookResponse,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def update(
|
|
43
|
+
self,
|
|
44
|
+
webhook_id: str,
|
|
45
|
+
payload: models.WebhookUpdateRequest | dict[str, Any],
|
|
46
|
+
) -> models.WebhookResponse:
|
|
47
|
+
return self._client._request(
|
|
48
|
+
"PATCH",
|
|
49
|
+
f"/api/v1/webhooks/subscriptions/{webhook_id}",
|
|
50
|
+
json_body=payload,
|
|
51
|
+
response_model=models.WebhookResponse,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def delete(self, webhook_id: str) -> None:
|
|
55
|
+
self._client._request("DELETE", f"/api/v1/webhooks/subscriptions/{webhook_id}")
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
def list_events(
|
|
59
|
+
self,
|
|
60
|
+
webhook_id: str,
|
|
61
|
+
*,
|
|
62
|
+
limit: int | None = None,
|
|
63
|
+
offset: int | None = None,
|
|
64
|
+
) -> models.WebhookEventListResponse:
|
|
65
|
+
return self._client._request(
|
|
66
|
+
"GET",
|
|
67
|
+
f"/api/v1/webhooks/subscriptions/{webhook_id}/events",
|
|
68
|
+
params={"limit": limit, "offset": offset},
|
|
69
|
+
response_model=models.WebhookEventListResponse,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def ping(self, webhook_id: str) -> models.PingWebhookResponse:
|
|
73
|
+
return self._client._request(
|
|
74
|
+
"POST",
|
|
75
|
+
f"/api/v1/webhooks/subscriptions/{webhook_id}/ping",
|
|
76
|
+
response_model=models.PingWebhookResponse,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
__all__ = ["WebhookSubscriptionsResource"]
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from .. import models
|
|
4
|
-
from .base import BaseResource
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class DevicesResource(BaseResource):
|
|
8
|
-
def list(
|
|
9
|
-
self,
|
|
10
|
-
*,
|
|
11
|
-
limit: int | None = None,
|
|
12
|
-
offset: int | None = None,
|
|
13
|
-
status: str | None = None,
|
|
14
|
-
search: str | None = None,
|
|
15
|
-
sort_by: str | None = None,
|
|
16
|
-
sort_order: str | None = None,
|
|
17
|
-
) -> models.DeviceListResponse:
|
|
18
|
-
return self._client._request(
|
|
19
|
-
"GET",
|
|
20
|
-
"/api/v1/devices",
|
|
21
|
-
params={
|
|
22
|
-
"limit": limit,
|
|
23
|
-
"offset": offset,
|
|
24
|
-
"status": status,
|
|
25
|
-
"search": search,
|
|
26
|
-
"sort_by": sort_by,
|
|
27
|
-
"sort_order": sort_order,
|
|
28
|
-
},
|
|
29
|
-
response_model=models.DeviceListResponse,
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
def get(self, device_id: str) -> models.DeviceResponse:
|
|
33
|
-
return self._client._request(
|
|
34
|
-
"GET",
|
|
35
|
-
f"/api/v1/devices/{device_id}",
|
|
36
|
-
response_model=models.DeviceResponse,
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
__all__ = ["DevicesResource"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|