Relayforge is a small, production-minded webhook delivery service. It accepts idempotent events, signs outbound payloads with HMAC-SHA256, persists work in SQLite, retries recoverable failures with exponential backoff, and retains exhausted deliveries in a dead-letter state.
Webhook sending looks simple until a receiver times out, a client retries a request, or a worker crashes midway through a send. Relayforge makes those failure modes explicit:
- idempotency is enforced per endpoint and client key;
- dispatch is claimed transactionally before it is sent;
- outbound requests have a strict timeout and a signed envelope;
- non-2xx results are retried with capped exponential backoff;
- stale claims become retryable after their visibility window expires.
Requires Node.js 22 or newer.
cp .env.example .env
npm install
npm run dev
Create an endpoint:
curl -X POST http://localhost:3000/v1/endpoints \
-H 'content-type: application/json' \
-d '{"url":"https://webhook.site/your-id","secret":"replace-with-a-long-random-secret"}'
Enqueue an event with an idempotency key:
curl -X POST http://localhost:3000/v1/deliveries \
-H 'content-type: application/json' \
-H 'idempotency-key: order-1001-created' \
-d '{"endpointId":"ENDPOINT_ID","eventType":"order.created","payload":{"orderId":"ord_1001"}}'
Run one dispatch batch:
curl -X POST http://localhost:3000/v1/workers/dispatch
| Method | Route | Purpose |
|---|---|---|
| GET | /healthz | Liveness probe |
| GET | /v1/endpoints | List endpoint metadata |
| POST | /v1/endpoints | Register a signed callback endpoint |
| GET | /v1/deliveries | Inspect recent deliveries |
| GET | /v1/deliveries/:deliveryId | Inspect one delivery |
| POST | /v1/deliveries | Enqueue an idempotent event |
| POST | /v1/workers/dispatch | Dispatch a bounded batch |
If ADMIN_TOKEN is set, the worker route requires the same value in the x-admin-token header.
The receiver gets a JSON body shaped as:
{
"id": "delivery UUID",
"event": "order.created",
"occurredAt": "2026-08-09T12:00:00.000Z",
"data": { "orderId": "ord_1001" }
}
The x-relayforge-signature header is sha256= followed by the HMAC-SHA256 digest of the exact request body. Compare it with a constant-time algorithm at the receiver.
npm run check
The check combines strict TypeScript type checking, the Node test suite, and a production build. The CI workflow runs the same command.
See docs/architecture.md for the execution model and SECURITY.md for operational boundaries.
Relayforge is deliberately a focused reference implementation. For a multi-node deployment, use PostgreSQL or another shared durable store, run dispatch through a process supervisor, enforce egress controls at the network layer, store endpoint secrets in a managed secret service, and expose metrics to your monitoring platform.