Python client for Hookrail — durable, at-least-once webhook delivery.
Project description
hookrail-python
Python client for Hookrail — durable, at-least-once webhook delivery. Covers the public producer surface: send events, check delivery status, and verify incoming webhook signatures.
Install
pip install hookrail
# or
uv add hookrail
Requires Python 3.10–3.13.
Quickstart (sync)
from hookrail import Hookrail
with Hookrail(api_key="hk_...", base_url="https://hooks.example.com") as client:
accepted = client.send_event("orders.created", {"order_id": "o_1", "amount": 4200})
print("event:", accepted.event_id, "replayed:", accepted.replayed)
status = client.get_event(accepted.event_id)
for d in status.deliveries:
print(d.delivery_id, d.state)
Quickstart (async)
import asyncio
from hookrail import AsyncHookrail
async def main() -> None:
async with AsyncHookrail(api_key="hk_...", base_url="https://hooks.example.com") as client:
accepted = await client.send_event("orders.created", {"order_id": "o_1"})
print(accepted.event_id)
asyncio.run(main())
Error model
Every SDK error derives from HookrailError.
| Exception | HTTP status | Meaning |
|---|---|---|
HookrailConfigError |
— | Invalid client construction (missing key, bad URL, etc.) |
HookrailConnectionError |
— | Connect / DNS / TLS failure |
HookrailTimeoutError |
— | Connect / read / write timeout |
BadRequestError |
400 | Malformed request body or topic |
AuthenticationError |
401 | Missing or invalid hk_… producer key |
NotFoundError |
404 | Event not found (also masks certain server outages — see caveats) |
ConflictError |
409 | Idempotency key collision with different payload bytes |
PayloadTooLargeError |
413 | Event payload exceeds server limit |
RateLimitError |
429 | Rate limited; carries retry_after (seconds) |
ServerError |
5xx | Server-side error |
RetryError |
— | All retries exhausted; wraps the last error as __cause__ |
HTTP 4xx errors that are not retried: 400, 401, 404, 409, 413.
Retry and idempotency
- Automatic retries on transport errors, 408, 425, 429, and all 5xx statuses.
- Full-jitter capped exponential backoff with configurable
RetryPolicy. TheRetry-Afterheader is honoured as a floor (jitter applied on top). - Byte-identical retries: if the server has already processed the event
(same idempotency key + identical raw bytes), you receive a
202withreplayed=True— no error. If the bytes differ, a409 Conflictis returned. - Idempotency keys are automatically generated per request. You do not need to supply one.
Verifying webhook signatures
from hookrail import verify_signature
from hookrail.signing import HEADER, SignatureError
def handle(headers: dict[str, str], delivery_id: str, raw_body: bytes, secret: bytes) -> bool:
try:
verify_signature(secret, headers[HEADER], delivery_id, raw_body)
except SignatureError:
return False
return True
The verify_signature helper supports dual-secret rotation (pass a list of
bytes), configurable timestamp tolerance (default 300 s), and raises typed
exceptions (SignatureError, SignatureTimestampError,
MalformedSignatureError).
Caveats / residual risk
get_eventreturning 404 can mask a transient server outage (known server bug). Production code should treat a 404 fromget_eventas ambiguous — the event may still have been accepted.- Per-worker rate limits apply at the server; the client respects
Retry-Afterbut does not coordinate across processes.
License
Apache-2.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hookrail-0.1.0.tar.gz.
File metadata
- Download URL: hookrail-0.1.0.tar.gz
- Upload date:
- Size: 90.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93b133f0ade0ddb241e56f5e666bc32078fe1e317133e89ed63d77fb3ed66c56
|
|
| MD5 |
aa3350acb08f11550f994ee08d410710
|
|
| BLAKE2b-256 |
a41daa97db3d1833b4cfdf2882eb9aed14e2f2a4ef3e095a7ac95a90aff6a874
|
Provenance
The following attestation bundles were made for hookrail-0.1.0.tar.gz:
Publisher:
release.yml on mit112/hookrail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hookrail-0.1.0.tar.gz -
Subject digest:
93b133f0ade0ddb241e56f5e666bc32078fe1e317133e89ed63d77fb3ed66c56 - Sigstore transparency entry: 1867628033
- Sigstore integration time:
-
Permalink:
mit112/hookrail@38bb4120b2921d7f8a02cf4457696b006fc7469d -
Branch / Tag:
refs/tags/python-v0.1.0 - Owner: https://github.com/mit112
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@38bb4120b2921d7f8a02cf4457696b006fc7469d -
Trigger Event:
push
-
Statement type:
File details
Details for the file hookrail-0.1.0-py3-none-any.whl.
File metadata
- Download URL: hookrail-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6bd6cd01f67238b6e0142714ac0d4c1275d411ddbcb58768235298190c5ea97c
|
|
| MD5 |
0031860d8876d97bdae376671820bf53
|
|
| BLAKE2b-256 |
bb63b75fc764b940b086500daecb7d7dad845424de3c602ce39fe8adf8cda219
|
Provenance
The following attestation bundles were made for hookrail-0.1.0-py3-none-any.whl:
Publisher:
release.yml on mit112/hookrail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hookrail-0.1.0-py3-none-any.whl -
Subject digest:
6bd6cd01f67238b6e0142714ac0d4c1275d411ddbcb58768235298190c5ea97c - Sigstore transparency entry: 1867628140
- Sigstore integration time:
-
Permalink:
mit112/hookrail@38bb4120b2921d7f8a02cf4457696b006fc7469d -
Branch / Tag:
refs/tags/python-v0.1.0 - Owner: https://github.com/mit112
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@38bb4120b2921d7f8a02cf4457696b006fc7469d -
Trigger Event:
push
-
Statement type: