Skip to main content

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.

Metadata

Release files for hookrail 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hookrail 0.1.0
File Size Uploaded
hookrail-0.1.0.tar.gz 90.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hookrail 0.1.0
File Interpreter ABI Platform
hookrail-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 107.6 kB

Release files / hookrail-0.1.0.tar.gz

Download URL hookrail-0.1.0.tar.gz
Size 90.4 kB
Tags Source
SHA-256 checksum
How to use checksums
93b133f0ade0ddb241e56f5e666bc32078fe1e317133e89ed63d77fb3ed66c56
BLAKE2b-256 checksum
How to use checksums
a41daa97db3d1833b4cfdf2882eb9aed14e2f2a4ef3e095a7ac95a90aff6a874
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.

Transparency log

Release files / hookrail-0.1.0-py3-none-any.whl

Download URL hookrail-0.1.0-py3-none-any.whl
Size 17.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6bd6cd01f67238b6e0142714ac0d4c1275d411ddbcb58768235298190c5ea97c
BLAKE2b-256 checksum
How to use checksums
bb63b75fc764b940b086500daecb7d7dad845424de3c602ce39fe8adf8cda219
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page