Skip to main content

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. The Retry-After header 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 202 with replayed=True — no error. If the bytes differ, a 409 Conflict is 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_event returning 404 can mask a transient server outage (known server bug). Production code should treat a 404 from get_event as ambiguous — the event may still have been accepted.
  • Per-worker rate limits apply at the server; the client respects Retry-After but does not coordinate across processes.

License

Apache-2.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hookrail-0.1.0.tar.gz (90.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hookrail-0.1.0-py3-none-any.whl (17.2 kB view details)

Uploaded Python 3

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

Hashes for hookrail-0.1.0.tar.gz
Algorithm Hash digest
SHA256 93b133f0ade0ddb241e56f5e666bc32078fe1e317133e89ed63d77fb3ed66c56
MD5 aa3350acb08f11550f994ee08d410710
BLAKE2b-256 a41daa97db3d1833b4cfdf2882eb9aed14e2f2a4ef3e095a7ac95a90aff6a874

See more details on using hashes here.

Provenance

The following attestation bundles were made for hookrail-0.1.0.tar.gz:

Publisher: release.yml on mit112/hookrail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for hookrail-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6bd6cd01f67238b6e0142714ac0d4c1275d411ddbcb58768235298190c5ea97c
MD5 0031860d8876d97bdae376671820bf53
BLAKE2b-256 bb63b75fc764b940b086500daecb7d7dad845424de3c602ce39fe8adf8cda219

See more details on using hashes here.

Provenance

The following attestation bundles were made for hookrail-0.1.0-py3-none-any.whl:

Publisher: release.yml on mit112/hookrail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page