Stafett is a self-hosted delivery worker for HTTP callbacks. Run it beside your app: it saves each job in your Postgres, then delivers the request with retries, exponential backoff, and a dead-letter queue.
curl -X POST http://localhost:8000/enqueue \
-H 'content-type: application/json' \
-H 'stafett-url: http://receiver:9000/' \
--data-binary '{"order":42}'
A 202 means the job committed. Delivery is at-least-once, so destinations deduplicate on webhook-id or an id of your own.
Five attempts and exponential backoff, applied only to failures worth repeating. The queue and its history live in your Postgres.
Optional Standard Webhooks signing over the exact bytes Stafett sends. Verify it when the destination is yours.
Exhausted jobs are held, not dropped. Replay after the endpoint is healthy again.
Use GET /jobs/{id} for one job and pgq to inspect, replay, and maintain the queue in your database.
Scale enqueue and delivery independently. Enqueue pods do not hold the signing secret; delivery pods do not serve enqueue traffic.
Keep the unauthenticated API inside your network. Payloads are any UTF-8 body up to 1 MiB, with up to 50 forwarded headers.
With a signing secret set, every delivery carries the three Standard Webhooks headers. The webhook-id is a delivery identifier and stays the same across retries: use it as your idempotency key when you own the endpoint.
POST /hooks/ship HTTP/1.1
webhook-id: 018f3b7c-6c4a-7b32-9f21-2c0a5e4d9b11
webhook-timestamp: 1770000000
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=
content-type: application/json
{"order":42}
Stafett is a delivery queue, not a compute platform or a workflow engine. It stores the job in your Postgres and POSTs to the URL you named; the destination does the work. Reach for something else when you need: