webhook-platform 2.0.0__tar.gz → 2.2.1__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.
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/PKG-INFO +59 -1
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/README.md +58 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/hookflow/__init__.py +1 -1
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/hookflow/client.py +26 -1
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/pyproject.toml +1 -1
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/tests/test_client.py +29 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/webhook_platform.egg-info/PKG-INFO +59 -1
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/hookflow/errors.py +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/hookflow/types.py +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/hookflow/webhooks.py +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/setup.cfg +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/tests/__init__.py +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/tests/test_incoming.py +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/tests/test_webhooks.py +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/webhook_platform.egg-info/SOURCES.txt +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/webhook_platform.egg-info/dependency_links.txt +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/webhook_platform.egg-info/requires.txt +0 -0
- {webhook_platform-2.0.0 → webhook_platform-2.2.1}/webhook_platform.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: webhook-platform
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Official Python SDK for Hookflow — reliable webhook infrastructure
|
|
5
5
|
Author-email: Vadym Kykalo <vadymkykalo@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -338,6 +338,64 @@ except HookflowError as e:
|
|
|
338
338
|
print(f"Error {e.status}: {e.message}")
|
|
339
339
|
```
|
|
340
340
|
|
|
341
|
+
### Error Response Format
|
|
342
|
+
|
|
343
|
+
All API errors return a consistent JSON body:
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{
|
|
347
|
+
"error": "error_code",
|
|
348
|
+
"message": "Human-readable description",
|
|
349
|
+
"status": 400,
|
|
350
|
+
"fieldErrors": { "field": "reason" }
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
- **`error`** — machine-readable error code (`snake_case`), always present
|
|
355
|
+
- **`message`** — human-readable description, always present
|
|
356
|
+
- **`status`** — HTTP status code (integer), always present
|
|
357
|
+
- **`fieldErrors`** — field-level validation details (only present for `validation_error`)
|
|
358
|
+
|
|
359
|
+
### Error Codes Reference
|
|
360
|
+
|
|
361
|
+
| HTTP Status | `error` Code | SDK Exception | Description |
|
|
362
|
+
|---|---|---|---|
|
|
363
|
+
| 400 | `validation_error` | `ValidationError` | Invalid request parameters; see `fieldErrors` |
|
|
364
|
+
| 400 | `invalid_request` | `HookflowError` | Malformed or semantically invalid request |
|
|
365
|
+
| 401 | `unauthorized` | `AuthenticationError` | Missing or invalid API key / expired token |
|
|
366
|
+
| 403 | `forbidden` | `HookflowError` | Insufficient permissions for the action |
|
|
367
|
+
| 404 | `not_found` | `NotFoundError` | Requested resource does not exist |
|
|
368
|
+
| 413 | `payload_too_large` | `HookflowError` | Request body exceeds maximum allowed size |
|
|
369
|
+
| 422 | `unprocessable_entity` | `HookflowError` | Valid syntax but violates business rules |
|
|
370
|
+
| 429 | `rate_limit_exceeded` | `RateLimitError` | Too many requests; check `X-RateLimit-*` headers |
|
|
371
|
+
| 500 | `internal_error` | `HookflowError` | Unexpected server error |
|
|
372
|
+
|
|
373
|
+
## Generic Requests
|
|
374
|
+
|
|
375
|
+
As the API expands, you can call any endpoint directly without waiting for SDK updates:
|
|
376
|
+
|
|
377
|
+
```python
|
|
378
|
+
# GET
|
|
379
|
+
schemas = client.get("/api/v1/projects/proj_123/schemas")
|
|
380
|
+
|
|
381
|
+
# GET with query params
|
|
382
|
+
items = client.get("/api/v1/projects/proj_123/items", params={"status": "active"})
|
|
383
|
+
|
|
384
|
+
# POST with body and idempotency key
|
|
385
|
+
result = client.post("/api/v1/some/new/endpoint", body={"key": "value"}, idempotency_key="unique-key")
|
|
386
|
+
|
|
387
|
+
# PUT
|
|
388
|
+
client.put("/api/v1/projects/proj_123/settings", body={"timezone": "UTC"})
|
|
389
|
+
|
|
390
|
+
# PATCH
|
|
391
|
+
client.patch("/api/v1/projects/proj_123/settings", body={"timezone": "UTC"})
|
|
392
|
+
|
|
393
|
+
# DELETE
|
|
394
|
+
client.delete("/api/v1/projects/proj_123/tags/old-tag")
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
All generic methods use the same authentication, error handling, and rate-limit logic as the built-in methods.
|
|
398
|
+
|
|
341
399
|
## Configuration
|
|
342
400
|
|
|
343
401
|
```python
|
|
@@ -309,6 +309,64 @@ except HookflowError as e:
|
|
|
309
309
|
print(f"Error {e.status}: {e.message}")
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
+
### Error Response Format
|
|
313
|
+
|
|
314
|
+
All API errors return a consistent JSON body:
|
|
315
|
+
|
|
316
|
+
```json
|
|
317
|
+
{
|
|
318
|
+
"error": "error_code",
|
|
319
|
+
"message": "Human-readable description",
|
|
320
|
+
"status": 400,
|
|
321
|
+
"fieldErrors": { "field": "reason" }
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
- **`error`** — machine-readable error code (`snake_case`), always present
|
|
326
|
+
- **`message`** — human-readable description, always present
|
|
327
|
+
- **`status`** — HTTP status code (integer), always present
|
|
328
|
+
- **`fieldErrors`** — field-level validation details (only present for `validation_error`)
|
|
329
|
+
|
|
330
|
+
### Error Codes Reference
|
|
331
|
+
|
|
332
|
+
| HTTP Status | `error` Code | SDK Exception | Description |
|
|
333
|
+
|---|---|---|---|
|
|
334
|
+
| 400 | `validation_error` | `ValidationError` | Invalid request parameters; see `fieldErrors` |
|
|
335
|
+
| 400 | `invalid_request` | `HookflowError` | Malformed or semantically invalid request |
|
|
336
|
+
| 401 | `unauthorized` | `AuthenticationError` | Missing or invalid API key / expired token |
|
|
337
|
+
| 403 | `forbidden` | `HookflowError` | Insufficient permissions for the action |
|
|
338
|
+
| 404 | `not_found` | `NotFoundError` | Requested resource does not exist |
|
|
339
|
+
| 413 | `payload_too_large` | `HookflowError` | Request body exceeds maximum allowed size |
|
|
340
|
+
| 422 | `unprocessable_entity` | `HookflowError` | Valid syntax but violates business rules |
|
|
341
|
+
| 429 | `rate_limit_exceeded` | `RateLimitError` | Too many requests; check `X-RateLimit-*` headers |
|
|
342
|
+
| 500 | `internal_error` | `HookflowError` | Unexpected server error |
|
|
343
|
+
|
|
344
|
+
## Generic Requests
|
|
345
|
+
|
|
346
|
+
As the API expands, you can call any endpoint directly without waiting for SDK updates:
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
# GET
|
|
350
|
+
schemas = client.get("/api/v1/projects/proj_123/schemas")
|
|
351
|
+
|
|
352
|
+
# GET with query params
|
|
353
|
+
items = client.get("/api/v1/projects/proj_123/items", params={"status": "active"})
|
|
354
|
+
|
|
355
|
+
# POST with body and idempotency key
|
|
356
|
+
result = client.post("/api/v1/some/new/endpoint", body={"key": "value"}, idempotency_key="unique-key")
|
|
357
|
+
|
|
358
|
+
# PUT
|
|
359
|
+
client.put("/api/v1/projects/proj_123/settings", body={"timezone": "UTC"})
|
|
360
|
+
|
|
361
|
+
# PATCH
|
|
362
|
+
client.patch("/api/v1/projects/proj_123/settings", body={"timezone": "UTC"})
|
|
363
|
+
|
|
364
|
+
# DELETE
|
|
365
|
+
client.delete("/api/v1/projects/proj_123/tags/old-tag")
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
All generic methods use the same authentication, error handling, and rate-limit logic as the built-in methods.
|
|
369
|
+
|
|
312
370
|
## Configuration
|
|
313
371
|
|
|
314
372
|
```python
|
|
@@ -37,7 +37,7 @@ from .errors import (
|
|
|
37
37
|
|
|
38
38
|
DEFAULT_BASE_URL = "http://localhost:8080"
|
|
39
39
|
DEFAULT_TIMEOUT = 30
|
|
40
|
-
SDK_VERSION = "2.
|
|
40
|
+
SDK_VERSION = "2.2.1"
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class Hookflow:
|
|
@@ -63,6 +63,31 @@ class Hookflow:
|
|
|
63
63
|
self.incoming_sources = IncomingSources(self)
|
|
64
64
|
self.incoming_events = IncomingEventsApi(self)
|
|
65
65
|
|
|
66
|
+
def get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
67
|
+
"""Generic GET request. Use for endpoints not yet covered by the SDK."""
|
|
68
|
+
return self._request("GET", path, params=params)
|
|
69
|
+
|
|
70
|
+
def post(
|
|
71
|
+
self,
|
|
72
|
+
path: str,
|
|
73
|
+
body: Optional[Dict[str, Any]] = None,
|
|
74
|
+
idempotency_key: Optional[str] = None,
|
|
75
|
+
) -> Any:
|
|
76
|
+
"""Generic POST request. Use for endpoints not yet covered by the SDK."""
|
|
77
|
+
return self._request("POST", path, body=body, idempotency_key=idempotency_key)
|
|
78
|
+
|
|
79
|
+
def put(self, path: str, body: Optional[Dict[str, Any]] = None) -> Any:
|
|
80
|
+
"""Generic PUT request. Use for endpoints not yet covered by the SDK."""
|
|
81
|
+
return self._request("PUT", path, body=body)
|
|
82
|
+
|
|
83
|
+
def patch(self, path: str, body: Optional[Dict[str, Any]] = None) -> Any:
|
|
84
|
+
"""Generic PATCH request. Use for endpoints not yet covered by the SDK."""
|
|
85
|
+
return self._request("PATCH", path, body=body)
|
|
86
|
+
|
|
87
|
+
def delete(self, path: str) -> Any:
|
|
88
|
+
"""Generic DELETE request. Use for endpoints not yet covered by the SDK."""
|
|
89
|
+
return self._request("DELETE", path)
|
|
90
|
+
|
|
66
91
|
def _request(
|
|
67
92
|
self,
|
|
68
93
|
method: str,
|
|
@@ -74,6 +74,35 @@ class TestHookflowClient:
|
|
|
74
74
|
assert client.deliveries is not None
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
class TestGenericRequestMethods:
|
|
78
|
+
"""Tests for generic request methods."""
|
|
79
|
+
|
|
80
|
+
def test_exposes_get_method(self):
|
|
81
|
+
"""Should expose public get method."""
|
|
82
|
+
client = Hookflow(api_key="test_api_key")
|
|
83
|
+
assert callable(client.get)
|
|
84
|
+
|
|
85
|
+
def test_exposes_post_method(self):
|
|
86
|
+
"""Should expose public post method."""
|
|
87
|
+
client = Hookflow(api_key="test_api_key")
|
|
88
|
+
assert callable(client.post)
|
|
89
|
+
|
|
90
|
+
def test_exposes_put_method(self):
|
|
91
|
+
"""Should expose public put method."""
|
|
92
|
+
client = Hookflow(api_key="test_api_key")
|
|
93
|
+
assert callable(client.put)
|
|
94
|
+
|
|
95
|
+
def test_exposes_patch_method(self):
|
|
96
|
+
"""Should expose public patch method."""
|
|
97
|
+
client = Hookflow(api_key="test_api_key")
|
|
98
|
+
assert callable(client.patch)
|
|
99
|
+
|
|
100
|
+
def test_exposes_delete_method(self):
|
|
101
|
+
"""Should expose public delete method."""
|
|
102
|
+
client = Hookflow(api_key="test_api_key")
|
|
103
|
+
assert callable(client.delete)
|
|
104
|
+
|
|
105
|
+
|
|
77
106
|
class TestErrorClasses:
|
|
78
107
|
"""Tests for error classes."""
|
|
79
108
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: webhook-platform
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Official Python SDK for Hookflow — reliable webhook infrastructure
|
|
5
5
|
Author-email: Vadym Kykalo <vadymkykalo@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -338,6 +338,64 @@ except HookflowError as e:
|
|
|
338
338
|
print(f"Error {e.status}: {e.message}")
|
|
339
339
|
```
|
|
340
340
|
|
|
341
|
+
### Error Response Format
|
|
342
|
+
|
|
343
|
+
All API errors return a consistent JSON body:
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{
|
|
347
|
+
"error": "error_code",
|
|
348
|
+
"message": "Human-readable description",
|
|
349
|
+
"status": 400,
|
|
350
|
+
"fieldErrors": { "field": "reason" }
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
- **`error`** — machine-readable error code (`snake_case`), always present
|
|
355
|
+
- **`message`** — human-readable description, always present
|
|
356
|
+
- **`status`** — HTTP status code (integer), always present
|
|
357
|
+
- **`fieldErrors`** — field-level validation details (only present for `validation_error`)
|
|
358
|
+
|
|
359
|
+
### Error Codes Reference
|
|
360
|
+
|
|
361
|
+
| HTTP Status | `error` Code | SDK Exception | Description |
|
|
362
|
+
|---|---|---|---|
|
|
363
|
+
| 400 | `validation_error` | `ValidationError` | Invalid request parameters; see `fieldErrors` |
|
|
364
|
+
| 400 | `invalid_request` | `HookflowError` | Malformed or semantically invalid request |
|
|
365
|
+
| 401 | `unauthorized` | `AuthenticationError` | Missing or invalid API key / expired token |
|
|
366
|
+
| 403 | `forbidden` | `HookflowError` | Insufficient permissions for the action |
|
|
367
|
+
| 404 | `not_found` | `NotFoundError` | Requested resource does not exist |
|
|
368
|
+
| 413 | `payload_too_large` | `HookflowError` | Request body exceeds maximum allowed size |
|
|
369
|
+
| 422 | `unprocessable_entity` | `HookflowError` | Valid syntax but violates business rules |
|
|
370
|
+
| 429 | `rate_limit_exceeded` | `RateLimitError` | Too many requests; check `X-RateLimit-*` headers |
|
|
371
|
+
| 500 | `internal_error` | `HookflowError` | Unexpected server error |
|
|
372
|
+
|
|
373
|
+
## Generic Requests
|
|
374
|
+
|
|
375
|
+
As the API expands, you can call any endpoint directly without waiting for SDK updates:
|
|
376
|
+
|
|
377
|
+
```python
|
|
378
|
+
# GET
|
|
379
|
+
schemas = client.get("/api/v1/projects/proj_123/schemas")
|
|
380
|
+
|
|
381
|
+
# GET with query params
|
|
382
|
+
items = client.get("/api/v1/projects/proj_123/items", params={"status": "active"})
|
|
383
|
+
|
|
384
|
+
# POST with body and idempotency key
|
|
385
|
+
result = client.post("/api/v1/some/new/endpoint", body={"key": "value"}, idempotency_key="unique-key")
|
|
386
|
+
|
|
387
|
+
# PUT
|
|
388
|
+
client.put("/api/v1/projects/proj_123/settings", body={"timezone": "UTC"})
|
|
389
|
+
|
|
390
|
+
# PATCH
|
|
391
|
+
client.patch("/api/v1/projects/proj_123/settings", body={"timezone": "UTC"})
|
|
392
|
+
|
|
393
|
+
# DELETE
|
|
394
|
+
client.delete("/api/v1/projects/proj_123/tags/old-tag")
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
All generic methods use the same authentication, error handling, and rate-limit logic as the built-in methods.
|
|
398
|
+
|
|
341
399
|
## Configuration
|
|
342
400
|
|
|
343
401
|
```python
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{webhook_platform-2.0.0 → webhook_platform-2.2.1}/webhook_platform.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|