hooksniff 0.1.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.
@@ -0,0 +1,242 @@
1
+ Metadata-Version: 2.4
2
+ Name: hooksniff
3
+ Version: 0.1.0
4
+ Summary: Official Python client for HookSniff webhook delivery service
5
+ Home-page: https://github.com/hooksniff/hooksniff
6
+ Author: HookSniff
7
+ Author-email: support@hooksniff.dev
8
+ License: MIT
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: requests>=2.28.0
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: home-page
28
+ Dynamic: license
29
+ Dynamic: requires-dist
30
+ Dynamic: requires-python
31
+ Dynamic: summary
32
+
33
+ # HookSniff Python SDK
34
+
35
+ Official Python client for the [HookSniff](https://hooksniff.vercel.app) webhook delivery service.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install hooksniff
41
+ ```
42
+
43
+ Or install from source:
44
+
45
+ ```bash
46
+ cd sdks/python
47
+ pip install -e .
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ```python
53
+ from hooksniff import HookSniffClient
54
+
55
+ # Initialize client
56
+ client = HookSniffClient(api_key="hr_live_your_api_key_here")
57
+
58
+ # Create a webhook endpoint
59
+ endpoint = client.endpoints.create(
60
+ url="https://myapp.com/webhook",
61
+ description="Order notifications",
62
+ )
63
+ print(f"Endpoint created: {endpoint.id}")
64
+
65
+ # Send a webhook
66
+ delivery = client.webhooks.send(
67
+ endpoint_id=endpoint.id,
68
+ event="order.created",
69
+ data={"order_id": "12345", "amount": 99.99},
70
+ )
71
+ print(f"Delivery queued: {delivery.id}, status: {delivery.status}")
72
+
73
+ # Check delivery status
74
+ status = client.webhooks.get(delivery.id)
75
+ print(f"Status: {status.status}, attempts: {status.attempt_count}")
76
+
77
+ # List deliveries
78
+ deliveries = client.webhooks.list(status="failed", page=1)
79
+ for d in deliveries.deliveries:
80
+ print(f" {d.id}: {d.status}")
81
+
82
+ # Replay a failed delivery
83
+ replayed = client.webhooks.replay(delivery.id)
84
+ print(f"Replay queued: {replayed.id}")
85
+ ```
86
+
87
+ ## Batch Webhooks
88
+
89
+ Send multiple webhooks in a single request (max 100):
90
+
91
+ ```python
92
+ results = client.webhooks.batch([
93
+ {
94
+ "endpoint_id": "ep_1",
95
+ "event": "order.created",
96
+ "data": {"order_id": "12345"},
97
+ },
98
+ {
99
+ "endpoint_id": "ep_2",
100
+ "event": "payment.completed",
101
+ "data": {"payment_id": "pay_67890"},
102
+ },
103
+ ])
104
+
105
+ print(f"Delivered: {len(results.deliveries)}")
106
+ print(f"Errors: {len(results.errors)}")
107
+ for err in results.errors:
108
+ print(f" Item {err['index']}: {err['error']}")
109
+ ```
110
+
111
+ ## Retry Policy
112
+
113
+ Configure custom retry behavior when creating endpoints:
114
+
115
+ ```python
116
+ from hooksniff import HookSniffClient
117
+ from hooksniff.models import RetryPolicy
118
+
119
+ client = HookSniffClient(api_key="hr_live_...")
120
+
121
+ endpoint = client.endpoints.create(
122
+ url="https://myapp.com/webhook",
123
+ description="Critical notifications",
124
+ retry_policy=RetryPolicy(
125
+ max_attempts=5,
126
+ backoff="exponential",
127
+ initial_delay_secs=10,
128
+ max_delay_secs=3600,
129
+ ),
130
+ )
131
+ ```
132
+
133
+ ## Delivery Attempts
134
+
135
+ Inspect individual delivery attempts:
136
+
137
+ ```python
138
+ attempts = client.webhooks.attempts(delivery.id)
139
+ for attempt in attempts:
140
+ print(f" Attempt {attempt.attempt_number}: status={attempt.status_code}, "
141
+ f"duration={attempt.duration_ms}ms")
142
+ if attempt.error_message:
143
+ print(f" Error: {attempt.error_message}")
144
+ ```
145
+
146
+ ## Export Logs
147
+
148
+ Export webhook logs as JSON or CSV:
149
+
150
+ ```python
151
+ # JSON export
152
+ logs = client.webhooks.export(format="json", status="failed")
153
+
154
+ # CSV export
155
+ csv_data = client.webhooks.export(format="csv", date_from="2024-01-01")
156
+ with open("webhooks.csv", "w") as f:
157
+ f.write(csv_data)
158
+ ```
159
+
160
+ ## Signature Verification
161
+
162
+ Verify incoming webhook signatures in your handler:
163
+
164
+ ```python
165
+ from hooksniff import verify_signature
166
+
167
+ # In your webhook handler
168
+ def handle_webhook(request):
169
+ payload = request.body.decode("utf-8")
170
+ signature = request.headers.get("X-HookSniff-Signature", "")
171
+ secret = "whsec_your_endpoint_signing_secret"
172
+
173
+ if not verify_signature(payload, signature, secret):
174
+ return {"error": "Invalid signature"}, 401
175
+
176
+ # Process the webhook
177
+ data = json.loads(payload)
178
+ print(f"Received event: {data['event']}")
179
+ return {"received": True}, 200
180
+ ```
181
+
182
+ ## Error Handling
183
+
184
+ ```python
185
+ from hooksniff import (
186
+ HookSniffClient,
187
+ AuthenticationError,
188
+ NotFoundError,
189
+ RateLimitError,
190
+ ValidationError,
191
+ PayloadTooLargeError,
192
+ )
193
+
194
+ client = HookSniffClient(api_key="hr_live_...")
195
+
196
+ try:
197
+ delivery = client.webhooks.send(
198
+ endpoint_id="nonexistent",
199
+ data={"test": True},
200
+ )
201
+ except AuthenticationError:
202
+ print("Invalid API key")
203
+ except NotFoundError:
204
+ print("Endpoint not found")
205
+ except RateLimitError:
206
+ print("Rate limit exceeded - try again later")
207
+ except ValidationError as e:
208
+ print(f"Invalid request: {e.message}")
209
+ except PayloadTooLargeError:
210
+ print("Payload exceeds maximum size")
211
+ ```
212
+
213
+ ## API Reference
214
+
215
+ ### `HookSniffClient(api_key, base_url="https://hooksniff-api-1046140057667.europe-west1.run.app/v1", timeout=30)`
216
+
217
+ Main client class.
218
+
219
+ ### `client.endpoints`
220
+
221
+ - `.create(url, description=None, retry_policy=None)` → `Endpoint`
222
+ - `.get(endpoint_id)` → `Endpoint`
223
+ - `.list()` → `List[Endpoint]`
224
+ - `.delete(endpoint_id)` → `bool`
225
+
226
+ ### `client.webhooks`
227
+
228
+ - `.send(endpoint_id, event=None, data=None)` → `Delivery`
229
+ - `.get(delivery_id)` → `Delivery`
230
+ - `.list(status=None, page=1, per_page=20)` → `DeliveryList`
231
+ - `.replay(delivery_id)` → `Delivery`
232
+ - `.batch(webhooks)` → `BatchResult`
233
+ - `.attempts(delivery_id)` → `List[DeliveryAttempt]`
234
+ - `.export(format="json", status=None, date_from=None, date_to=None)` → `Any`
235
+
236
+ ### `verify_signature(payload, signature, secret)` → `bool`
237
+
238
+ Verify a webhook signature using HMAC-SHA256.
239
+
240
+ ## License
241
+
242
+ MIT
@@ -0,0 +1,210 @@
1
+ # HookSniff Python SDK
2
+
3
+ Official Python client for the [HookSniff](https://hooksniff.vercel.app) webhook delivery service.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install hooksniff
9
+ ```
10
+
11
+ Or install from source:
12
+
13
+ ```bash
14
+ cd sdks/python
15
+ pip install -e .
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```python
21
+ from hooksniff import HookSniffClient
22
+
23
+ # Initialize client
24
+ client = HookSniffClient(api_key="hr_live_your_api_key_here")
25
+
26
+ # Create a webhook endpoint
27
+ endpoint = client.endpoints.create(
28
+ url="https://myapp.com/webhook",
29
+ description="Order notifications",
30
+ )
31
+ print(f"Endpoint created: {endpoint.id}")
32
+
33
+ # Send a webhook
34
+ delivery = client.webhooks.send(
35
+ endpoint_id=endpoint.id,
36
+ event="order.created",
37
+ data={"order_id": "12345", "amount": 99.99},
38
+ )
39
+ print(f"Delivery queued: {delivery.id}, status: {delivery.status}")
40
+
41
+ # Check delivery status
42
+ status = client.webhooks.get(delivery.id)
43
+ print(f"Status: {status.status}, attempts: {status.attempt_count}")
44
+
45
+ # List deliveries
46
+ deliveries = client.webhooks.list(status="failed", page=1)
47
+ for d in deliveries.deliveries:
48
+ print(f" {d.id}: {d.status}")
49
+
50
+ # Replay a failed delivery
51
+ replayed = client.webhooks.replay(delivery.id)
52
+ print(f"Replay queued: {replayed.id}")
53
+ ```
54
+
55
+ ## Batch Webhooks
56
+
57
+ Send multiple webhooks in a single request (max 100):
58
+
59
+ ```python
60
+ results = client.webhooks.batch([
61
+ {
62
+ "endpoint_id": "ep_1",
63
+ "event": "order.created",
64
+ "data": {"order_id": "12345"},
65
+ },
66
+ {
67
+ "endpoint_id": "ep_2",
68
+ "event": "payment.completed",
69
+ "data": {"payment_id": "pay_67890"},
70
+ },
71
+ ])
72
+
73
+ print(f"Delivered: {len(results.deliveries)}")
74
+ print(f"Errors: {len(results.errors)}")
75
+ for err in results.errors:
76
+ print(f" Item {err['index']}: {err['error']}")
77
+ ```
78
+
79
+ ## Retry Policy
80
+
81
+ Configure custom retry behavior when creating endpoints:
82
+
83
+ ```python
84
+ from hooksniff import HookSniffClient
85
+ from hooksniff.models import RetryPolicy
86
+
87
+ client = HookSniffClient(api_key="hr_live_...")
88
+
89
+ endpoint = client.endpoints.create(
90
+ url="https://myapp.com/webhook",
91
+ description="Critical notifications",
92
+ retry_policy=RetryPolicy(
93
+ max_attempts=5,
94
+ backoff="exponential",
95
+ initial_delay_secs=10,
96
+ max_delay_secs=3600,
97
+ ),
98
+ )
99
+ ```
100
+
101
+ ## Delivery Attempts
102
+
103
+ Inspect individual delivery attempts:
104
+
105
+ ```python
106
+ attempts = client.webhooks.attempts(delivery.id)
107
+ for attempt in attempts:
108
+ print(f" Attempt {attempt.attempt_number}: status={attempt.status_code}, "
109
+ f"duration={attempt.duration_ms}ms")
110
+ if attempt.error_message:
111
+ print(f" Error: {attempt.error_message}")
112
+ ```
113
+
114
+ ## Export Logs
115
+
116
+ Export webhook logs as JSON or CSV:
117
+
118
+ ```python
119
+ # JSON export
120
+ logs = client.webhooks.export(format="json", status="failed")
121
+
122
+ # CSV export
123
+ csv_data = client.webhooks.export(format="csv", date_from="2024-01-01")
124
+ with open("webhooks.csv", "w") as f:
125
+ f.write(csv_data)
126
+ ```
127
+
128
+ ## Signature Verification
129
+
130
+ Verify incoming webhook signatures in your handler:
131
+
132
+ ```python
133
+ from hooksniff import verify_signature
134
+
135
+ # In your webhook handler
136
+ def handle_webhook(request):
137
+ payload = request.body.decode("utf-8")
138
+ signature = request.headers.get("X-HookSniff-Signature", "")
139
+ secret = "whsec_your_endpoint_signing_secret"
140
+
141
+ if not verify_signature(payload, signature, secret):
142
+ return {"error": "Invalid signature"}, 401
143
+
144
+ # Process the webhook
145
+ data = json.loads(payload)
146
+ print(f"Received event: {data['event']}")
147
+ return {"received": True}, 200
148
+ ```
149
+
150
+ ## Error Handling
151
+
152
+ ```python
153
+ from hooksniff import (
154
+ HookSniffClient,
155
+ AuthenticationError,
156
+ NotFoundError,
157
+ RateLimitError,
158
+ ValidationError,
159
+ PayloadTooLargeError,
160
+ )
161
+
162
+ client = HookSniffClient(api_key="hr_live_...")
163
+
164
+ try:
165
+ delivery = client.webhooks.send(
166
+ endpoint_id="nonexistent",
167
+ data={"test": True},
168
+ )
169
+ except AuthenticationError:
170
+ print("Invalid API key")
171
+ except NotFoundError:
172
+ print("Endpoint not found")
173
+ except RateLimitError:
174
+ print("Rate limit exceeded - try again later")
175
+ except ValidationError as e:
176
+ print(f"Invalid request: {e.message}")
177
+ except PayloadTooLargeError:
178
+ print("Payload exceeds maximum size")
179
+ ```
180
+
181
+ ## API Reference
182
+
183
+ ### `HookSniffClient(api_key, base_url="https://hooksniff-api-1046140057667.europe-west1.run.app/v1", timeout=30)`
184
+
185
+ Main client class.
186
+
187
+ ### `client.endpoints`
188
+
189
+ - `.create(url, description=None, retry_policy=None)` → `Endpoint`
190
+ - `.get(endpoint_id)` → `Endpoint`
191
+ - `.list()` → `List[Endpoint]`
192
+ - `.delete(endpoint_id)` → `bool`
193
+
194
+ ### `client.webhooks`
195
+
196
+ - `.send(endpoint_id, event=None, data=None)` → `Delivery`
197
+ - `.get(delivery_id)` → `Delivery`
198
+ - `.list(status=None, page=1, per_page=20)` → `DeliveryList`
199
+ - `.replay(delivery_id)` → `Delivery`
200
+ - `.batch(webhooks)` → `BatchResult`
201
+ - `.attempts(delivery_id)` → `List[DeliveryAttempt]`
202
+ - `.export(format="json", status=None, date_from=None, date_to=None)` → `Any`
203
+
204
+ ### `verify_signature(payload, signature, secret)` → `bool`
205
+
206
+ Verify a webhook signature using HMAC-SHA256.
207
+
208
+ ## License
209
+
210
+ MIT
@@ -0,0 +1,72 @@
1
+ """
2
+ HookSniff Python SDK - Enterprise webhook delivery service client.
3
+ """
4
+
5
+ from .client import HookSniffClient
6
+ from .models import (
7
+ Endpoint,
8
+ Delivery,
9
+ DeliveryAttempt,
10
+ DeliveryList,
11
+ BatchResult,
12
+ Stats,
13
+ RetryPolicy,
14
+ OrderCreatedPayload,
15
+ OrderCompletedPayload,
16
+ PaymentFailedPayload,
17
+ PaymentSucceededPayload,
18
+ UserRegisteredPayload,
19
+ UserUpdatedPayload,
20
+ InvoiceCreatedPayload,
21
+ )
22
+ from .exceptions import (
23
+ HookSniffError,
24
+ AuthenticationError,
25
+ NotFoundError,
26
+ RateLimitError,
27
+ ValidationError,
28
+ PayloadTooLargeError,
29
+ )
30
+ from .utils import verify_signature, verify_webhook_signature, WebhookHandler
31
+ from .verify import (
32
+ WebhookEvent,
33
+ WebhookVerifier,
34
+ verify_webhook,
35
+ verify_webhook_request,
36
+ )
37
+
38
+ __version__ = "0.1.0"
39
+ __all__ = [
40
+ "HookSniffClient",
41
+ # Models
42
+ "Endpoint",
43
+ "Delivery",
44
+ "DeliveryAttempt",
45
+ "DeliveryList",
46
+ "BatchResult",
47
+ "Stats",
48
+ # Webhook payload types
49
+ "OrderCreatedPayload",
50
+ "OrderCompletedPayload",
51
+ "PaymentFailedPayload",
52
+ "PaymentSucceededPayload",
53
+ "UserRegisteredPayload",
54
+ "UserUpdatedPayload",
55
+ "InvoiceCreatedPayload",
56
+ # Exceptions
57
+ "HookSniffError",
58
+ "AuthenticationError",
59
+ "NotFoundError",
60
+ "RateLimitError",
61
+ "ValidationError",
62
+ "PayloadTooLargeError",
63
+ # Legacy webhook verification (utils)
64
+ "verify_signature",
65
+ "verify_webhook_signature",
66
+ "WebhookHandler",
67
+ # Standard Webhooks verification (verify)
68
+ "WebhookEvent",
69
+ "WebhookVerifier",
70
+ "verify_webhook",
71
+ "verify_webhook_request",
72
+ ]