gl-speech-sdk 0.0.1b1__py3-none-any.whl
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.
- gl_speech_sdk/__init__.py +69 -0
- gl_speech_sdk/client.py +86 -0
- gl_speech_sdk/models.py +409 -0
- gl_speech_sdk/py.typed +0 -0
- gl_speech_sdk/stt.py +456 -0
- gl_speech_sdk/tts.py +449 -0
- gl_speech_sdk/webhooks.py +551 -0
- gl_speech_sdk-0.0.1b1.dist-info/METADATA +417 -0
- gl_speech_sdk-0.0.1b1.dist-info/RECORD +11 -0
- gl_speech_sdk-0.0.1b1.dist-info/WHEEL +4 -0
- gl_speech_sdk-0.0.1b1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
"""Webhook handling for the GL Speech Python client.
|
|
2
|
+
|
|
3
|
+
This module provides the Webhooks class for handling webhook operations
|
|
4
|
+
with the Prosa Speech API, including endpoint management, event handling,
|
|
5
|
+
and delivery management.
|
|
6
|
+
|
|
7
|
+
Authors:
|
|
8
|
+
GDP Labs
|
|
9
|
+
|
|
10
|
+
References:
|
|
11
|
+
https://docs2.prosa.ai/speech/webhook/rest/api/
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
from typing import Any
|
|
16
|
+
from urllib.parse import urljoin
|
|
17
|
+
|
|
18
|
+
import httpx
|
|
19
|
+
|
|
20
|
+
from gl_speech_sdk.models import (
|
|
21
|
+
DeliveryTicket,
|
|
22
|
+
WebhookDelivery,
|
|
23
|
+
WebhookEndpoint,
|
|
24
|
+
WebhookEndpointCreate,
|
|
25
|
+
WebhookEndpointListing,
|
|
26
|
+
WebhookEndpointUpdate,
|
|
27
|
+
WebhookEvent,
|
|
28
|
+
WebhookEventListing,
|
|
29
|
+
WebhookRotation,
|
|
30
|
+
WebhookRotationPeriod,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Webhooks:
|
|
37
|
+
"""Handles Webhook API operations for the Prosa Speech API."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, client):
|
|
40
|
+
"""Initialize Webhooks API.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
client: SpeechClient instance
|
|
44
|
+
"""
|
|
45
|
+
self._client = client
|
|
46
|
+
|
|
47
|
+
def _prepare_headers(
|
|
48
|
+
self, extra_headers: dict[str, str] | None = None
|
|
49
|
+
) -> dict[str, str]:
|
|
50
|
+
"""Prepare headers for the API request.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
extra_headers (dict[str, str] | None): Additional headers to merge with default headers
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
dict[str, str]: Dictionary containing the request headers
|
|
57
|
+
"""
|
|
58
|
+
headers = self._client.default_headers.copy()
|
|
59
|
+
|
|
60
|
+
if self._client.api_key:
|
|
61
|
+
headers["x-api-key"] = self._client.api_key
|
|
62
|
+
|
|
63
|
+
if extra_headers:
|
|
64
|
+
headers.update(extra_headers)
|
|
65
|
+
|
|
66
|
+
return headers
|
|
67
|
+
|
|
68
|
+
def _make_request(
|
|
69
|
+
self,
|
|
70
|
+
method: str,
|
|
71
|
+
url: str,
|
|
72
|
+
headers: dict[str, str],
|
|
73
|
+
json_data: dict[str, Any] | None = None,
|
|
74
|
+
params: dict[str, Any] | None = None,
|
|
75
|
+
) -> dict[str, Any] | list[dict[str, Any]] | int:
|
|
76
|
+
"""Make an HTTP request to the API.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
method (str): HTTP method (GET, POST, DELETE, PUT)
|
|
80
|
+
url (str): Request URL
|
|
81
|
+
headers (dict[str, str]): Request headers
|
|
82
|
+
json_data (dict[str, Any] | None): JSON body data
|
|
83
|
+
params (dict[str, Any] | None): Query parameters
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
dict[str, Any] | list[dict[str, Any]] | int: Response JSON data
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
httpx.HTTPStatusError: If the request fails
|
|
90
|
+
"""
|
|
91
|
+
timeout = httpx.Timeout(self._client.timeout)
|
|
92
|
+
|
|
93
|
+
logger.debug("Request: %s %s", method, url)
|
|
94
|
+
logger.debug("Headers: %s", headers)
|
|
95
|
+
if json_data:
|
|
96
|
+
logger.debug("Body: %s", json_data)
|
|
97
|
+
|
|
98
|
+
with httpx.Client(timeout=timeout) as client:
|
|
99
|
+
response = client.request(
|
|
100
|
+
method=method,
|
|
101
|
+
url=url,
|
|
102
|
+
headers=headers,
|
|
103
|
+
json=json_data,
|
|
104
|
+
params=params,
|
|
105
|
+
)
|
|
106
|
+
response.raise_for_status()
|
|
107
|
+
|
|
108
|
+
if response.status_code == 204 or not response.content:
|
|
109
|
+
return {}
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
data = response.json()
|
|
113
|
+
except Exception:
|
|
114
|
+
return {}
|
|
115
|
+
|
|
116
|
+
if not isinstance(data, (dict, list, int)):
|
|
117
|
+
raise TypeError(f"Unexpected response type: {type(data)}")
|
|
118
|
+
return data
|
|
119
|
+
|
|
120
|
+
# =========================================================================
|
|
121
|
+
# Endpoint Management
|
|
122
|
+
# =========================================================================
|
|
123
|
+
|
|
124
|
+
def list_endpoints(
|
|
125
|
+
self,
|
|
126
|
+
extra_headers: dict[str, str] | None = None,
|
|
127
|
+
) -> list[WebhookEndpointListing]:
|
|
128
|
+
"""List all webhook endpoints.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
list[WebhookEndpointListing]: List of webhook endpoints
|
|
135
|
+
|
|
136
|
+
Raises:
|
|
137
|
+
httpx.HTTPStatusError: If the API request fails
|
|
138
|
+
"""
|
|
139
|
+
logger.debug("Listing webhook endpoints")
|
|
140
|
+
|
|
141
|
+
url = urljoin(self._client.base_url, "webhooks/endpoints")
|
|
142
|
+
headers = self._prepare_headers(extra_headers)
|
|
143
|
+
|
|
144
|
+
response_data = self._make_request("GET", url, headers)
|
|
145
|
+
if not isinstance(response_data, list):
|
|
146
|
+
return []
|
|
147
|
+
return [WebhookEndpointListing(**item) for item in response_data]
|
|
148
|
+
|
|
149
|
+
def create_endpoint(
|
|
150
|
+
self,
|
|
151
|
+
url: str,
|
|
152
|
+
event_filters: list[str] | None = None,
|
|
153
|
+
ssl_verification: bool | None = True,
|
|
154
|
+
secret_key: str | None = None,
|
|
155
|
+
extra_headers: dict[str, str] | None = None,
|
|
156
|
+
) -> WebhookEndpoint:
|
|
157
|
+
"""Create a new webhook endpoint.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
url (str): Callback URL for webhook events
|
|
161
|
+
event_filters (list[str] | None): Event types to filter. Empty = all events.
|
|
162
|
+
ssl_verification (bool | None): Verify SSL certificate. Default: True.
|
|
163
|
+
secret_key (str | None): Secret key for signing. Empty = auto-generated.
|
|
164
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
WebhookEndpoint: Created webhook endpoint with secrets
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
ValueError: If url is empty
|
|
171
|
+
httpx.HTTPStatusError: If the API request fails
|
|
172
|
+
"""
|
|
173
|
+
if not url:
|
|
174
|
+
raise ValueError("url cannot be empty")
|
|
175
|
+
|
|
176
|
+
logger.debug("Creating webhook endpoint: %s", url)
|
|
177
|
+
|
|
178
|
+
endpoint_url = urljoin(self._client.base_url, "webhooks/endpoints")
|
|
179
|
+
headers = self._prepare_headers(extra_headers)
|
|
180
|
+
|
|
181
|
+
request = WebhookEndpointCreate(
|
|
182
|
+
url=url,
|
|
183
|
+
event_filters=event_filters,
|
|
184
|
+
ssl_verification=ssl_verification,
|
|
185
|
+
secret_key=secret_key,
|
|
186
|
+
)
|
|
187
|
+
json_data = request.model_dump(exclude_none=True)
|
|
188
|
+
|
|
189
|
+
response_data = self._make_request("POST", endpoint_url, headers, json_data)
|
|
190
|
+
if not isinstance(response_data, dict):
|
|
191
|
+
raise TypeError("Expected dict response from API")
|
|
192
|
+
return WebhookEndpoint(**response_data)
|
|
193
|
+
|
|
194
|
+
def get_endpoint(
|
|
195
|
+
self,
|
|
196
|
+
endpoint_id: str,
|
|
197
|
+
extra_headers: dict[str, str] | None = None,
|
|
198
|
+
) -> WebhookEndpoint:
|
|
199
|
+
"""Get details of a specific webhook endpoint.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
endpoint_id (str): Unique identifier of the endpoint
|
|
203
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
WebhookEndpoint: Webhook endpoint details with secrets
|
|
207
|
+
|
|
208
|
+
Raises:
|
|
209
|
+
ValueError: If endpoint_id is empty
|
|
210
|
+
httpx.HTTPStatusError: If the API request fails
|
|
211
|
+
"""
|
|
212
|
+
if not endpoint_id:
|
|
213
|
+
raise ValueError("endpoint_id cannot be empty")
|
|
214
|
+
|
|
215
|
+
logger.debug("Getting webhook endpoint: %s", endpoint_id)
|
|
216
|
+
|
|
217
|
+
url = urljoin(self._client.base_url, f"webhooks/endpoints/{endpoint_id}")
|
|
218
|
+
headers = self._prepare_headers(extra_headers)
|
|
219
|
+
|
|
220
|
+
response_data = self._make_request("GET", url, headers)
|
|
221
|
+
if not isinstance(response_data, dict):
|
|
222
|
+
raise TypeError("Expected dict response from API")
|
|
223
|
+
return WebhookEndpoint(**response_data)
|
|
224
|
+
|
|
225
|
+
def update_endpoint(
|
|
226
|
+
self,
|
|
227
|
+
endpoint_id: str,
|
|
228
|
+
url: str | None = None,
|
|
229
|
+
event_filters: list[str] | None = None,
|
|
230
|
+
ssl_verification: bool | None = True,
|
|
231
|
+
extra_headers: dict[str, str] | None = None,
|
|
232
|
+
) -> WebhookEndpoint:
|
|
233
|
+
"""Update an existing webhook endpoint.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
endpoint_id (str): Unique identifier of the endpoint
|
|
237
|
+
url (str | None): Callback URL for webhook events
|
|
238
|
+
event_filters (list[str] | None): Event types to filter. Empty = all events.
|
|
239
|
+
ssl_verification (bool | None): Verify SSL certificate. Default: True.
|
|
240
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
WebhookEndpoint: Updated webhook endpoint
|
|
244
|
+
|
|
245
|
+
Raises:
|
|
246
|
+
ValueError: If endpoint_id is empty
|
|
247
|
+
httpx.HTTPStatusError: If the API request fails
|
|
248
|
+
"""
|
|
249
|
+
if not endpoint_id:
|
|
250
|
+
raise ValueError("endpoint_id cannot be empty")
|
|
251
|
+
|
|
252
|
+
logger.debug("Updating webhook endpoint: %s", endpoint_id)
|
|
253
|
+
|
|
254
|
+
endpoint_url = urljoin(self._client.base_url, f"webhooks/endpoints/{endpoint_id}")
|
|
255
|
+
headers = self._prepare_headers(extra_headers)
|
|
256
|
+
|
|
257
|
+
request = WebhookEndpointUpdate(
|
|
258
|
+
url=url,
|
|
259
|
+
event_filters=event_filters,
|
|
260
|
+
ssl_verification=ssl_verification,
|
|
261
|
+
)
|
|
262
|
+
json_data = request.model_dump(exclude_none=True)
|
|
263
|
+
|
|
264
|
+
response_data = self._make_request("PUT", endpoint_url, headers, json_data)
|
|
265
|
+
if not isinstance(response_data, dict):
|
|
266
|
+
raise TypeError("Expected dict response from API")
|
|
267
|
+
return WebhookEndpoint(**response_data)
|
|
268
|
+
|
|
269
|
+
def delete_endpoint(
|
|
270
|
+
self,
|
|
271
|
+
endpoint_id: str,
|
|
272
|
+
extra_headers: dict[str, str] | None = None,
|
|
273
|
+
) -> WebhookEndpoint:
|
|
274
|
+
"""Delete a webhook endpoint.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
endpoint_id (str): Unique identifier of the endpoint
|
|
278
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
WebhookEndpoint: Deleted webhook endpoint details
|
|
282
|
+
|
|
283
|
+
Raises:
|
|
284
|
+
ValueError: If endpoint_id is empty
|
|
285
|
+
httpx.HTTPStatusError: If the API request fails
|
|
286
|
+
"""
|
|
287
|
+
if not endpoint_id:
|
|
288
|
+
raise ValueError("endpoint_id cannot be empty")
|
|
289
|
+
|
|
290
|
+
logger.debug("Deleting webhook endpoint: %s", endpoint_id)
|
|
291
|
+
|
|
292
|
+
url = urljoin(self._client.base_url, f"webhooks/endpoints/{endpoint_id}")
|
|
293
|
+
headers = self._prepare_headers(extra_headers)
|
|
294
|
+
|
|
295
|
+
response_data = self._make_request("DELETE", url, headers)
|
|
296
|
+
if not response_data:
|
|
297
|
+
# Return dummy but required fields if response is empty
|
|
298
|
+
return WebhookEndpoint(id=endpoint_id, url="", ssl_verification=True)
|
|
299
|
+
if not isinstance(response_data, dict):
|
|
300
|
+
raise TypeError("Expected dict response from API")
|
|
301
|
+
return WebhookEndpoint(**response_data)
|
|
302
|
+
|
|
303
|
+
def rotate_secret(
|
|
304
|
+
self,
|
|
305
|
+
endpoint_id: str,
|
|
306
|
+
days: int | None = 3,
|
|
307
|
+
hours: int | None = 0,
|
|
308
|
+
extra_headers: dict[str, str] | None = None,
|
|
309
|
+
) -> WebhookEndpoint:
|
|
310
|
+
"""Rotate the secret key for a webhook endpoint.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
endpoint_id (str): Unique identifier of the endpoint
|
|
314
|
+
days (int | None): Days old secret remains valid. Default: 3.
|
|
315
|
+
hours (int | None): Hours old secret remains valid. Default: 0.
|
|
316
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
WebhookEndpoint: Webhook endpoint with new and expiring secrets
|
|
320
|
+
|
|
321
|
+
Raises:
|
|
322
|
+
ValueError: If endpoint_id is empty
|
|
323
|
+
httpx.HTTPStatusError: If the API request fails
|
|
324
|
+
"""
|
|
325
|
+
if not endpoint_id:
|
|
326
|
+
raise ValueError("endpoint_id cannot be empty")
|
|
327
|
+
|
|
328
|
+
logger.debug("Rotating secret for webhook endpoint: %s", endpoint_id)
|
|
329
|
+
|
|
330
|
+
url = urljoin(self._client.base_url, f"webhooks/endpoints/{endpoint_id}/secret")
|
|
331
|
+
headers = self._prepare_headers(extra_headers)
|
|
332
|
+
|
|
333
|
+
period = WebhookRotationPeriod(days=days, hours=hours)
|
|
334
|
+
request = WebhookRotation(rotation_period=period)
|
|
335
|
+
json_data = request.model_dump(exclude_none=True)
|
|
336
|
+
|
|
337
|
+
response_data = self._make_request("POST", url, headers, json_data)
|
|
338
|
+
if not isinstance(response_data, dict):
|
|
339
|
+
raise TypeError("Expected dict response from API")
|
|
340
|
+
return WebhookEndpoint(**response_data)
|
|
341
|
+
|
|
342
|
+
# =========================================================================
|
|
343
|
+
# Event Handling
|
|
344
|
+
# =========================================================================
|
|
345
|
+
|
|
346
|
+
def list_events(
|
|
347
|
+
self,
|
|
348
|
+
from_date: str | None = None,
|
|
349
|
+
until_date: str | None = None,
|
|
350
|
+
extra_headers: dict[str, str] | None = None,
|
|
351
|
+
) -> list[WebhookEventListing]:
|
|
352
|
+
"""List webhook events.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
from_date (str | None): Filter events from this date (YYYY-MM-DD)
|
|
356
|
+
until_date (str | None): Filter events until this date (YYYY-MM-DD)
|
|
357
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
list[WebhookEventListing]: List of webhook events
|
|
361
|
+
|
|
362
|
+
Raises:
|
|
363
|
+
httpx.HTTPStatusError: If the API request fails
|
|
364
|
+
"""
|
|
365
|
+
logger.debug("Listing webhook events")
|
|
366
|
+
|
|
367
|
+
url = urljoin(self._client.base_url, "webhooks/events")
|
|
368
|
+
headers = self._prepare_headers(extra_headers)
|
|
369
|
+
|
|
370
|
+
params: dict[str, Any] = {}
|
|
371
|
+
if from_date is not None:
|
|
372
|
+
params["from_date"] = from_date
|
|
373
|
+
if until_date is not None:
|
|
374
|
+
params["until_date"] = until_date
|
|
375
|
+
|
|
376
|
+
response_data = self._make_request("GET", url, headers, params=params)
|
|
377
|
+
if not isinstance(response_data, list):
|
|
378
|
+
return []
|
|
379
|
+
return [WebhookEventListing(**item) for item in response_data]
|
|
380
|
+
|
|
381
|
+
def get_event(
|
|
382
|
+
self,
|
|
383
|
+
event_id: str,
|
|
384
|
+
extra_headers: dict[str, str] | None = None,
|
|
385
|
+
) -> WebhookEvent:
|
|
386
|
+
"""Get details of a specific webhook event.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
event_id (str): Unique identifier of the event
|
|
390
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
WebhookEvent: Webhook event details with data payload
|
|
394
|
+
|
|
395
|
+
Raises:
|
|
396
|
+
ValueError: If event_id is empty
|
|
397
|
+
httpx.HTTPStatusError: If the API request fails
|
|
398
|
+
"""
|
|
399
|
+
if not event_id:
|
|
400
|
+
raise ValueError("event_id cannot be empty")
|
|
401
|
+
|
|
402
|
+
logger.debug("Getting webhook event: %s", event_id)
|
|
403
|
+
|
|
404
|
+
url = urljoin(self._client.base_url, f"webhooks/events/{event_id}")
|
|
405
|
+
headers = self._prepare_headers(extra_headers)
|
|
406
|
+
|
|
407
|
+
response_data = self._make_request("GET", url, headers)
|
|
408
|
+
if not isinstance(response_data, dict):
|
|
409
|
+
raise TypeError("Expected dict response from API")
|
|
410
|
+
return WebhookEvent(**response_data)
|
|
411
|
+
|
|
412
|
+
def test_endpoint(
|
|
413
|
+
self,
|
|
414
|
+
endpoint_id: str,
|
|
415
|
+
extra_headers: dict[str, str] | None = None,
|
|
416
|
+
) -> DeliveryTicket:
|
|
417
|
+
"""Trigger a test event for a webhook endpoint.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
endpoint_id (str): Unique identifier of the endpoint
|
|
421
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
DeliveryTicket: Test event delivery ticket
|
|
425
|
+
|
|
426
|
+
Raises:
|
|
427
|
+
ValueError: If endpoint_id is empty
|
|
428
|
+
httpx.HTTPStatusError: If the API request fails
|
|
429
|
+
"""
|
|
430
|
+
if not endpoint_id:
|
|
431
|
+
raise ValueError("endpoint_id cannot be empty")
|
|
432
|
+
|
|
433
|
+
logger.debug("Testing webhook endpoint: %s", endpoint_id)
|
|
434
|
+
|
|
435
|
+
url = urljoin(self._client.base_url, f"webhooks/endpoints/{endpoint_id}/test")
|
|
436
|
+
headers = self._prepare_headers(extra_headers)
|
|
437
|
+
|
|
438
|
+
response_data = self._make_request("POST", url, headers)
|
|
439
|
+
if not isinstance(response_data, dict):
|
|
440
|
+
raise TypeError("Expected dict response from API")
|
|
441
|
+
return DeliveryTicket(**response_data)
|
|
442
|
+
|
|
443
|
+
# =========================================================================
|
|
444
|
+
# Delivery Management
|
|
445
|
+
# =========================================================================
|
|
446
|
+
|
|
447
|
+
def list_deliveries(
|
|
448
|
+
self,
|
|
449
|
+
endpoint_id: str,
|
|
450
|
+
from_date: str | None = None,
|
|
451
|
+
until_date: str | None = None,
|
|
452
|
+
extra_headers: dict[str, str] | None = None,
|
|
453
|
+
) -> list[WebhookDelivery]:
|
|
454
|
+
"""List webhook deliveries for an endpoint.
|
|
455
|
+
|
|
456
|
+
Args:
|
|
457
|
+
endpoint_id (str): Unique identifier of the endpoint
|
|
458
|
+
from_date (str | None): Filter deliveries from this date (YYYY-MM-DD)
|
|
459
|
+
until_date (str | None): Filter deliveries until this date (YYYY-MM-DD)
|
|
460
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
461
|
+
|
|
462
|
+
Returns:
|
|
463
|
+
list[WebhookDelivery]: List of webhook deliveries
|
|
464
|
+
|
|
465
|
+
Raises:
|
|
466
|
+
ValueError: If endpoint_id is empty
|
|
467
|
+
httpx.HTTPStatusError: If the API request fails
|
|
468
|
+
"""
|
|
469
|
+
if not endpoint_id:
|
|
470
|
+
raise ValueError("endpoint_id cannot be empty")
|
|
471
|
+
|
|
472
|
+
logger.debug("Listing webhook deliveries for endpoint: %s", endpoint_id)
|
|
473
|
+
|
|
474
|
+
url = urljoin(self._client.base_url, f"webhooks/endpoints/{endpoint_id}/deliveries")
|
|
475
|
+
headers = self._prepare_headers(extra_headers)
|
|
476
|
+
|
|
477
|
+
params: dict[str, Any] = {}
|
|
478
|
+
if from_date is not None:
|
|
479
|
+
params["from_date"] = from_date
|
|
480
|
+
if until_date is not None:
|
|
481
|
+
params["until_date"] = until_date
|
|
482
|
+
|
|
483
|
+
response_data = self._make_request("GET", url, headers, params=params)
|
|
484
|
+
if not isinstance(response_data, list):
|
|
485
|
+
return []
|
|
486
|
+
return [WebhookDelivery(**item) for item in response_data]
|
|
487
|
+
|
|
488
|
+
def replay_delivery(
|
|
489
|
+
self,
|
|
490
|
+
delivery_id: str,
|
|
491
|
+
extra_headers: dict[str, str] | None = None,
|
|
492
|
+
) -> DeliveryTicket:
|
|
493
|
+
"""Replay a specific webhook delivery.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
delivery_id (str): Unique identifier of the delivery
|
|
497
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
DeliveryTicket: Delivery ticket for the replayed event
|
|
501
|
+
|
|
502
|
+
Raises:
|
|
503
|
+
ValueError: If delivery_id is empty
|
|
504
|
+
httpx.HTTPStatusError: If the API request fails
|
|
505
|
+
"""
|
|
506
|
+
if not delivery_id:
|
|
507
|
+
raise ValueError("delivery_id cannot be empty")
|
|
508
|
+
|
|
509
|
+
logger.debug("Replaying webhook delivery: %s", delivery_id)
|
|
510
|
+
|
|
511
|
+
url = urljoin(self._client.base_url, f"webhooks/deliveries/{delivery_id}/replay")
|
|
512
|
+
headers = self._prepare_headers(extra_headers)
|
|
513
|
+
|
|
514
|
+
response_data = self._make_request("POST", url, headers)
|
|
515
|
+
if not isinstance(response_data, dict):
|
|
516
|
+
raise TypeError("Expected dict response from API")
|
|
517
|
+
return DeliveryTicket(**response_data)
|
|
518
|
+
|
|
519
|
+
def replay_failed_deliveries(
|
|
520
|
+
self,
|
|
521
|
+
endpoint_id: str,
|
|
522
|
+
extra_headers: dict[str, str] | None = None,
|
|
523
|
+
) -> list[DeliveryTicket]:
|
|
524
|
+
"""Replay all failed deliveries for an endpoint.
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
endpoint_id (str): Unique identifier of the endpoint
|
|
528
|
+
extra_headers (dict[str, str] | None): Additional headers
|
|
529
|
+
|
|
530
|
+
Returns:
|
|
531
|
+
list[DeliveryTicket]: List of new delivery tickets
|
|
532
|
+
|
|
533
|
+
Raises:
|
|
534
|
+
ValueError: If endpoint_id is empty
|
|
535
|
+
httpx.HTTPStatusError: If the API request fails
|
|
536
|
+
"""
|
|
537
|
+
if not endpoint_id:
|
|
538
|
+
raise ValueError("endpoint_id cannot be empty")
|
|
539
|
+
|
|
540
|
+
logger.debug("Replaying failed deliveries for endpoint: %s", endpoint_id)
|
|
541
|
+
|
|
542
|
+
url = urljoin(
|
|
543
|
+
self._client.base_url,
|
|
544
|
+
f"webhooks/endpoints/{endpoint_id}/replay-failed-deliveries"
|
|
545
|
+
)
|
|
546
|
+
headers = self._prepare_headers(extra_headers)
|
|
547
|
+
|
|
548
|
+
response_data = self._make_request("POST", url, headers)
|
|
549
|
+
if not isinstance(response_data, list):
|
|
550
|
+
return []
|
|
551
|
+
return [DeliveryTicket(**item) for item in response_data]
|