hooka-relay-python
Python 3.11+ client for Hooka Relay.
pip install hooka-relay-python
import os
from hooka_relay import HookaRelay
relay = HookaRelay(os.environ["HOOKA_API_KEY"])
event = relay.send_event({
"customerId": "cus_123", "type": "order.created", "payload": {"orderId": "123"},
"idempotencyKey": "order-123-created",
})
print(event["id"])
Use an application key with ingest permission. The customer ID must belong to that application; create customers in the dashboard or customer API before sending. Optional base_url and timeout (seconds, default 30) configure the client. Remote URLs require HTTPS; redirects are rejected to avoid credential forwarding. There are no implicit retries. Retry ambiguous network failures with the same explicit idempotencyKey; omitted keys are generated by the server, so resending without one can create another event.
HookaError exposes status, parsed body, and retry_after. Rate limits return 429, oversized requests 413, and schema failures 400 with failures: [{path, message}]. Payload limits: 256 KiB / JSON depth 32. TypedDict models are generated from the repository's OpenAPI contract; runtime server validation remains authoritative.
Verify and queue, then drain
verify_webhook(raw_body, headers, secret) uses the Standard Webhooks reference library. It raises on invalid signatures, a changed ID/body, or timestamps outside five minutes. Pass raw bytes and the displayed whsec_ secret. During rotation either old or new key verifies the dual signatures.
Minimal queue-and-drain receiver using the standard library (put a production HTTP server/reverse proxy in front of a real deployment). A bounded queue rejects overload with 503; accepted work is processed outside the request.
import os
import logging
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from queue import Queue, Full
from threading import Thread
from hooka_relay import verify_webhook
queue = Queue(maxsize=1000)
def process_event(item):
print(item["id"], item["payload"])
def drain():
while True:
item = queue.get()
try:
process_event(item)
except Exception:
logging.exception("Persist failed item to your dead-letter store: %s", item["id"])
finally:
queue.task_done()
class Receiver(BaseHTTPRequestHandler):
def do_POST(self):
if self.path != "/webhook":
self.send_error(404)
return
try:
length = int(self.headers.get("Content-Length", "-1"))
except ValueError:
self.send_error(400)
return
if length < 0 or self.headers.get("Transfer-Encoding"):
self.send_error(411)
return
if length > 262144:
self.send_error(413)
return
try:
headers = {k: self.headers.get(k, "") for k in ("webhook-id", "webhook-timestamp", "webhook-signature")}
payload = verify_webhook(self.rfile.read(length), headers, os.environ["HOOKA_SIGNING_SECRET"])
except Exception:
self.send_error(400)
return
try:
queue.put_nowait({"id": headers["webhook-id"], "payload": payload})
except Full:
self.send_error(503)
return
self.send_response(202)
self.end_headers()
Thread(target=drain, daemon=True).start()
ThreadingHTTPServer(("127.0.0.1", 8080), Receiver).serve_forever()
The queue is volatile: a crash loses already acknowledged work. For production, persist to a durable inbox/queue before acknowledging. Atomically deduplicate the authenticated webhook-id with business changes. Persist processing failures for retry or dead-letter handling; a log entry is not durable recovery.
Event ordering
Ordering is not guaranteed across retries or replay generations. The queue-and-drain example above separates acknowledgement from slow processing and isolates failures. It cannot restore producer order; apply per-entity sequence/version checks if required.
Release files for hooka-relay-python 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hooka_relay_python-2.0.0.tar.gz | 6.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hooka_relay_python-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.8 kB
Release files / hooka_relay_python-2.0.0.tar.gz
| Download URL | hooka_relay_python-2.0.0.tar.gz |
|---|---|
| Size | 6.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4695d9a7eef652c23538c44844a0d3b0889766d008790b771cb2c1d8e53b19f4
|
|
BLAKE2b-256 checksum How to use checksums |
1143675d35a390683f8a3f23096c3d99e49a36cdf7d0034f4c2475fe1b08a591
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 25, 2026.
Transparency logRelease files / hooka_relay_python-2.0.0-py3-none-any.whl
| Download URL | hooka_relay_python-2.0.0-py3-none-any.whl |
|---|---|
| Size | 6.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be4cba4995389f6eb8d2c762dadd0766aa4b3fc3449a98ffb288b8d99d1b33ff
|
|
BLAKE2b-256 checksum How to use checksums |
be9d09144fb95c270f0d306c5894e7c5e6133d4b47e7f5b15197d4c500c47624
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 25, 2026.
Transparency log