hookbridge 1.0.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,207 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
@@ -0,0 +1,241 @@
1
+ Metadata-Version: 2.4
2
+ Name: hookbridge
3
+ Version: 1.0.0
4
+ Summary: Official HookBridge SDK for Python
5
+ Project-URL: Homepage, https://hookbridge.io
6
+ Project-URL: Documentation, https://hookbridge.io/docs/sdks/python
7
+ Project-URL: Repository, https://github.com/hookbridge/hookbridge-python
8
+ Project-URL: Issues, https://github.com/hookbridge/hookbridge-python/issues
9
+ Author-email: HookBridge <support@hookbridge.io>
10
+ License-Expression: MIT
11
+ Keywords: api,hookbridge,sdk,webhook,webhooks
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
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
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Requires-Dist: httpx>=0.25.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.0; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
30
+ Requires-Dist: pytest-httpx>=0.21; extra == 'dev'
31
+ Requires-Dist: pytest>=7.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.1; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # HookBridge Python SDK
36
+
37
+ Official HookBridge SDK for Python. Send webhooks with guaranteed delivery, automatic retries, and full observability.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install hookbridge
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```python
48
+ from hookbridge import HookBridge
49
+
50
+ client = HookBridge(api_key="hb_live_xxxxxxxxxxxxxxxxxxxx")
51
+
52
+ # Send a webhook
53
+ result = client.send(
54
+ endpoint="https://customer.app/webhooks",
55
+ payload={
56
+ "event": "order.created",
57
+ "order_id": "ord_12345",
58
+ "amount": 99.99
59
+ }
60
+ )
61
+
62
+ print("Message ID:", result.message_id)
63
+ ```
64
+
65
+ ## Features
66
+
67
+ - **Guaranteed Delivery**: Webhooks are stored durably before acknowledgment
68
+ - **Automatic Retries**: Intelligent retry with exponential backoff
69
+ - **Idempotency**: Prevent duplicate webhook sends
70
+ - **Full Observability**: Query logs, metrics, and message status
71
+ - **Type Safety**: Full type hints with mypy support
72
+ - **Async Support**: Both sync and async clients available
73
+
74
+ ## Usage
75
+
76
+ ### Send a Webhook
77
+
78
+ ```python
79
+ result = client.send(
80
+ endpoint="https://customer.app/webhooks",
81
+ payload={"event": "user.created", "user_id": "usr_123"},
82
+ headers={"X-Tenant-Id": "tenant_abc"},
83
+ idempotency_key="user-123-created"
84
+ )
85
+ ```
86
+
87
+ ### Check Message Status
88
+
89
+ ```python
90
+ message = client.get_message(result.message_id)
91
+ print(message.status) # 'queued', 'succeeded', 'pending_retry', 'failed_permanent'
92
+ ```
93
+
94
+ ### Query Delivery Logs
95
+
96
+ ```python
97
+ from datetime import datetime
98
+
99
+ logs = client.get_logs(
100
+ status="failed_permanent",
101
+ start_time=datetime(2025, 1, 1),
102
+ limit=100
103
+ )
104
+
105
+ for msg in logs.messages:
106
+ print(msg.message_id, msg.last_error)
107
+ ```
108
+
109
+ ### Get Metrics
110
+
111
+ ```python
112
+ metrics = client.get_metrics("24h")
113
+ print(f"Success rate: {metrics.success_rate * 100:.1f}%")
114
+ print(f"Average latency: {metrics.avg_latency_ms}ms")
115
+ ```
116
+
117
+ ### Replay Failed Messages
118
+
119
+ ```python
120
+ # Replay a specific message
121
+ client.replay(message_id)
122
+
123
+ # Or replay from the Dead Letter Queue
124
+ dlq = client.get_dlq_messages()
125
+ for msg in dlq.messages:
126
+ client.replay_from_dlq(msg.message_id)
127
+ ```
128
+
129
+ ### Manage Retries
130
+
131
+ ```python
132
+ # Cancel a pending retry (moves to DLQ)
133
+ client.cancel_retry(message_id)
134
+
135
+ # Trigger immediate retry for a pending message
136
+ client.retry_now(message_id)
137
+ ```
138
+
139
+ ### API Key Management
140
+
141
+ ```python
142
+ # List API keys
143
+ keys = client.list_api_keys()
144
+
145
+ # Create a new API key
146
+ new_key = client.create_api_key(mode="live", label="Production backend")
147
+ print("Save this key:", new_key.key) # Only shown once!
148
+
149
+ # Delete an API key
150
+ client.delete_api_key("key_abc123")
151
+ ```
152
+
153
+ ## Async Usage
154
+
155
+ ```python
156
+ from hookbridge import AsyncHookBridge
157
+
158
+ async with AsyncHookBridge(api_key="hb_live_xxx") as client:
159
+ result = await client.send(
160
+ endpoint="https://customer.app/webhooks",
161
+ payload={"event": "order.created"}
162
+ )
163
+ ```
164
+
165
+ ## Configuration
166
+
167
+ ```python
168
+ client = HookBridge(
169
+ # Required: Your API key
170
+ api_key="hb_live_xxxxxxxxxxxxxxxxxxxx",
171
+
172
+ # Optional: Custom base URL (default: https://api.hookbridge.io)
173
+ base_url="https://api.hookbridge.io",
174
+
175
+ # Optional: Request timeout in seconds (default: 30)
176
+ timeout=30.0,
177
+
178
+ # Optional: Number of retries for failed requests (default: 3)
179
+ retries=3
180
+ )
181
+ ```
182
+
183
+ ## Error Handling
184
+
185
+ ```python
186
+ from hookbridge import (
187
+ HookBridge,
188
+ AuthenticationError,
189
+ ValidationError,
190
+ RateLimitError,
191
+ NotFoundError,
192
+ IdempotencyError
193
+ )
194
+
195
+ try:
196
+ client.send(...)
197
+ except AuthenticationError:
198
+ print("Invalid API key")
199
+ except ValidationError as e:
200
+ print(f"Invalid request: {e}")
201
+ except RateLimitError as e:
202
+ print(f"Rate limited. Retry after {e.retry_after}s")
203
+ except IdempotencyError:
204
+ print("Duplicate request with different payload")
205
+ ```
206
+
207
+ ## Webhook Delivery
208
+
209
+ When HookBridge delivers your webhook, it includes these headers:
210
+
211
+ - `X-Webhook-Signature`: HMAC-SHA256 signature for verification
212
+ - `X-Webhook-Id`: Message ID for tracking
213
+ - `X-Webhook-Timestamp`: Unix timestamp of the send request
214
+ - Any custom headers you specified
215
+
216
+ ### Retry Behavior
217
+
218
+ - **Fast retries** (for 429 responses): 30s, 60s, 120s, 240s, 300s
219
+ - **Slow retries** (for other errors): 30m, 2h, 6h, 12h, 24h, 48h, 72h, 96h
220
+ - Maximum 8 total attempts before moving to the Dead Letter Queue
221
+
222
+ ## Context Manager Support
223
+
224
+ ```python
225
+ # Sync
226
+ with HookBridge(api_key="...") as client:
227
+ client.send(...)
228
+
229
+ # Async
230
+ async with AsyncHookBridge(api_key="...") as client:
231
+ await client.send(...)
232
+ ```
233
+
234
+ ## Requirements
235
+
236
+ - Python 3.9 or later
237
+ - httpx
238
+
239
+ ## License
240
+
241
+ MIT
@@ -0,0 +1,207 @@
1
+ # HookBridge Python SDK
2
+
3
+ Official HookBridge SDK for Python. Send webhooks with guaranteed delivery, automatic retries, and full observability.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install hookbridge
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from hookbridge import HookBridge
15
+
16
+ client = HookBridge(api_key="hb_live_xxxxxxxxxxxxxxxxxxxx")
17
+
18
+ # Send a webhook
19
+ result = client.send(
20
+ endpoint="https://customer.app/webhooks",
21
+ payload={
22
+ "event": "order.created",
23
+ "order_id": "ord_12345",
24
+ "amount": 99.99
25
+ }
26
+ )
27
+
28
+ print("Message ID:", result.message_id)
29
+ ```
30
+
31
+ ## Features
32
+
33
+ - **Guaranteed Delivery**: Webhooks are stored durably before acknowledgment
34
+ - **Automatic Retries**: Intelligent retry with exponential backoff
35
+ - **Idempotency**: Prevent duplicate webhook sends
36
+ - **Full Observability**: Query logs, metrics, and message status
37
+ - **Type Safety**: Full type hints with mypy support
38
+ - **Async Support**: Both sync and async clients available
39
+
40
+ ## Usage
41
+
42
+ ### Send a Webhook
43
+
44
+ ```python
45
+ result = client.send(
46
+ endpoint="https://customer.app/webhooks",
47
+ payload={"event": "user.created", "user_id": "usr_123"},
48
+ headers={"X-Tenant-Id": "tenant_abc"},
49
+ idempotency_key="user-123-created"
50
+ )
51
+ ```
52
+
53
+ ### Check Message Status
54
+
55
+ ```python
56
+ message = client.get_message(result.message_id)
57
+ print(message.status) # 'queued', 'succeeded', 'pending_retry', 'failed_permanent'
58
+ ```
59
+
60
+ ### Query Delivery Logs
61
+
62
+ ```python
63
+ from datetime import datetime
64
+
65
+ logs = client.get_logs(
66
+ status="failed_permanent",
67
+ start_time=datetime(2025, 1, 1),
68
+ limit=100
69
+ )
70
+
71
+ for msg in logs.messages:
72
+ print(msg.message_id, msg.last_error)
73
+ ```
74
+
75
+ ### Get Metrics
76
+
77
+ ```python
78
+ metrics = client.get_metrics("24h")
79
+ print(f"Success rate: {metrics.success_rate * 100:.1f}%")
80
+ print(f"Average latency: {metrics.avg_latency_ms}ms")
81
+ ```
82
+
83
+ ### Replay Failed Messages
84
+
85
+ ```python
86
+ # Replay a specific message
87
+ client.replay(message_id)
88
+
89
+ # Or replay from the Dead Letter Queue
90
+ dlq = client.get_dlq_messages()
91
+ for msg in dlq.messages:
92
+ client.replay_from_dlq(msg.message_id)
93
+ ```
94
+
95
+ ### Manage Retries
96
+
97
+ ```python
98
+ # Cancel a pending retry (moves to DLQ)
99
+ client.cancel_retry(message_id)
100
+
101
+ # Trigger immediate retry for a pending message
102
+ client.retry_now(message_id)
103
+ ```
104
+
105
+ ### API Key Management
106
+
107
+ ```python
108
+ # List API keys
109
+ keys = client.list_api_keys()
110
+
111
+ # Create a new API key
112
+ new_key = client.create_api_key(mode="live", label="Production backend")
113
+ print("Save this key:", new_key.key) # Only shown once!
114
+
115
+ # Delete an API key
116
+ client.delete_api_key("key_abc123")
117
+ ```
118
+
119
+ ## Async Usage
120
+
121
+ ```python
122
+ from hookbridge import AsyncHookBridge
123
+
124
+ async with AsyncHookBridge(api_key="hb_live_xxx") as client:
125
+ result = await client.send(
126
+ endpoint="https://customer.app/webhooks",
127
+ payload={"event": "order.created"}
128
+ )
129
+ ```
130
+
131
+ ## Configuration
132
+
133
+ ```python
134
+ client = HookBridge(
135
+ # Required: Your API key
136
+ api_key="hb_live_xxxxxxxxxxxxxxxxxxxx",
137
+
138
+ # Optional: Custom base URL (default: https://api.hookbridge.io)
139
+ base_url="https://api.hookbridge.io",
140
+
141
+ # Optional: Request timeout in seconds (default: 30)
142
+ timeout=30.0,
143
+
144
+ # Optional: Number of retries for failed requests (default: 3)
145
+ retries=3
146
+ )
147
+ ```
148
+
149
+ ## Error Handling
150
+
151
+ ```python
152
+ from hookbridge import (
153
+ HookBridge,
154
+ AuthenticationError,
155
+ ValidationError,
156
+ RateLimitError,
157
+ NotFoundError,
158
+ IdempotencyError
159
+ )
160
+
161
+ try:
162
+ client.send(...)
163
+ except AuthenticationError:
164
+ print("Invalid API key")
165
+ except ValidationError as e:
166
+ print(f"Invalid request: {e}")
167
+ except RateLimitError as e:
168
+ print(f"Rate limited. Retry after {e.retry_after}s")
169
+ except IdempotencyError:
170
+ print("Duplicate request with different payload")
171
+ ```
172
+
173
+ ## Webhook Delivery
174
+
175
+ When HookBridge delivers your webhook, it includes these headers:
176
+
177
+ - `X-Webhook-Signature`: HMAC-SHA256 signature for verification
178
+ - `X-Webhook-Id`: Message ID for tracking
179
+ - `X-Webhook-Timestamp`: Unix timestamp of the send request
180
+ - Any custom headers you specified
181
+
182
+ ### Retry Behavior
183
+
184
+ - **Fast retries** (for 429 responses): 30s, 60s, 120s, 240s, 300s
185
+ - **Slow retries** (for other errors): 30m, 2h, 6h, 12h, 24h, 48h, 72h, 96h
186
+ - Maximum 8 total attempts before moving to the Dead Letter Queue
187
+
188
+ ## Context Manager Support
189
+
190
+ ```python
191
+ # Sync
192
+ with HookBridge(api_key="...") as client:
193
+ client.send(...)
194
+
195
+ # Async
196
+ async with AsyncHookBridge(api_key="...") as client:
197
+ await client.send(...)
198
+ ```
199
+
200
+ ## Requirements
201
+
202
+ - Python 3.9 or later
203
+ - httpx
204
+
205
+ ## License
206
+
207
+ MIT
@@ -0,0 +1,72 @@
1
+ """
2
+ HookBridge SDK for Python
3
+
4
+ Send webhooks with guaranteed delivery, automatic retries, and full observability.
5
+
6
+ Example:
7
+ >>> from hookbridge import HookBridge
8
+ >>>
9
+ >>> client = HookBridge(api_key="hb_live_xxxxxxxxxxxxxxxxxxxx")
10
+ >>>
11
+ >>> result = client.send(
12
+ ... endpoint="https://customer.app/webhooks",
13
+ ... payload={"event": "order.created", "order_id": "12345"}
14
+ ... )
15
+ >>> print(result.message_id)
16
+ """
17
+
18
+ from hookbridge.client import HookBridge, AsyncHookBridge
19
+ from hookbridge.types import (
20
+ SendWebhookResponse,
21
+ Message,
22
+ MessageSummary,
23
+ MessageStatus,
24
+ LogsResponse,
25
+ Metrics,
26
+ MetricsWindow,
27
+ APIKeyInfo,
28
+ APIKeyMode,
29
+ CreateAPIKeyResponse,
30
+ DLQMessagesResponse,
31
+ )
32
+ from hookbridge.errors import (
33
+ HookBridgeError,
34
+ AuthenticationError,
35
+ NotFoundError,
36
+ ValidationError,
37
+ RateLimitError,
38
+ IdempotencyError,
39
+ ReplayLimitError,
40
+ NetworkError,
41
+ TimeoutError,
42
+ )
43
+
44
+ __version__ = "1.0.0"
45
+
46
+ __all__ = [
47
+ # Client
48
+ "HookBridge",
49
+ "AsyncHookBridge",
50
+ # Types
51
+ "SendWebhookResponse",
52
+ "Message",
53
+ "MessageSummary",
54
+ "MessageStatus",
55
+ "LogsResponse",
56
+ "Metrics",
57
+ "MetricsWindow",
58
+ "APIKeyInfo",
59
+ "APIKeyMode",
60
+ "CreateAPIKeyResponse",
61
+ "DLQMessagesResponse",
62
+ # Errors
63
+ "HookBridgeError",
64
+ "AuthenticationError",
65
+ "NotFoundError",
66
+ "ValidationError",
67
+ "RateLimitError",
68
+ "IdempotencyError",
69
+ "ReplayLimitError",
70
+ "NetworkError",
71
+ "TimeoutError",
72
+ ]