Reliable outbound webhooks with inspectable retries, signed delivery, and durable evidence.
Open the live Relay demo · Watch the short demo · Read the case study
Sending an HTTP request is easy. Operating webhook delivery through timeouts, rate limits, duplicate execution, process interruption, secret rotation, and incident review is not.
Relay accepts authenticated events, persists fanout and outbox work atomically, publishes compact Queue messages, claims deliveries with leases, signs stable webhook requests, records each attempt, and schedules bounded retries. The result is an at-least-once delivery system whose behavior can be inspected instead of inferred.
The Relay demo includes a safe Failure Lab backed by Cloudflare Workers, D1, Queues, and Turnstile.
- Choose one of seven fixed receiver behaviors.
- Run the synthetic
order.createdevent. - Watch attempts and cryptographically verified receiver receipts appear together.
The demo accepts no custom URL or payload. Runs are globally and per-IP limited, expire after 30 minutes, and are removed by bounded cleanup. The owner Console remains authenticated by design.
flowchart LR
Client["Authenticated producer"] -->|"POST /v1/events"| Console["Relay Console Worker"]
Console -->|"atomic event + fanout + outbox"| D1[("Cloudflare D1")]
Console -->|"compact delivery ID"| Queue["Cloudflare Queue"]
Queue --> Consumer["Queue consumer"]
Consumer -->|"lease + signed HTTPS"| Receiver["Customer receiver"]
Consumer -->|"attempt evidence + retry time"| D1
Cron["One-minute Cron"] -->|"publish due outbox + cleanup"| D1
Consumer -. "free Service Binding" .-> Lab["Controlled Relay Lab Worker"]
Owner["Authenticated owner Console"] -->|"inspect + replay"| Console
The database is the durable source of truth; Queue messages carry identifiers, not payload copies. Retries reuse one stable webhook message ID while each attempt gets a fresh timestamp and signature. See the system architecture and ADRs.
- Guarantee: at least once; receivers must process idempotently.
- Atomic ingestion: event, fanout, and outbox rows commit in one D1 transaction.
- Lease recovery: expired claims can be safely reclaimed after interrupted execution.
- Bounded retries: HTTP-aware policy,
Retry-After, deterministic backoff, eight-attempt ceiling. - Stable identity: one webhook ID across retries, fresh signature timestamps per attempt.
- Replay lineage: manual replay creates new delivery work without erasing original evidence.
- Durable scheduling: D1 stores due time; Queue transports ready work.
- Strict public-HTTPS endpoint policy and signed endpoint verification.
- Standard Webhooks-compatible HMAC signatures.
- AES-GCM encrypted endpoint secrets with versioned Worker-held master keys and rotation overlap.
- Hashed API keys, owner session cookies, CSRF and same-origin enforcement.
- Redacted payload/header evidence in the operational Console.
- Managed, hostname-restricted Turnstile for the public demo.
- Free-only Cloudflare topology with application limits below provider ceilings.
Production was validated on 2026-08-09 at exactly $0 with no trial, custom domain, paid observability, or billing-dependent add-on. See the production evidence, cost guardrails, and threat model.
- TypeScript, React, Vite, Hono, Zod
- Cloudflare Workers, D1, Queues, Cron Triggers, Turnstile, Service Bindings
- Vitest and Cloudflare Workers test pool
- Playwright browser and accessibility coverage
- GitHub Actions with separate quality, database, Worker, security, and browser gates
apps/console/ React owner/public UI and Relay Worker
apps/lab/ Controlled webhook receiver Worker
packages/contracts/ Shared runtime schemas and TypeScript contracts
migrations/ Forward-only D1 schema history
tests/e2e/ Browser, responsive, accessibility, and Failure Lab tests
docs/ ADRs, architecture, threat model, production evidence
scripts/ Cost, publishing, provisioning, and media automation
Requirements: Node.js 22.22 or newer and Chromium.
npm ci
npx playwright install chromium
npm run db:migrate:local
npm run dev --workspace=apps/consoleIn a second terminal:
npm run dev --workspace=apps/labWorker secrets belong in ignored .dev.vars files. Production identifiers are rendered into ignored configuration files; credentials and recovery material must never be committed.
npm run format-check
npm run lint
npm run typecheck
npm test
npm run build
npm run check:cost
npm run check:publishing-safety
npm audit --omit=dev
npm run test:e2eCurrent release gate: 283 application/contract tests, 9 publishing/configuration/provisioning tests, 12 browser scenarios, zero production dependency vulnerabilities, and only two known warnings in generated Cloudflare types.
Phases 0-7 are complete. This branch is the production-validated v1 release candidate; the v1.0.0 tag is intentionally held until final human visual review of the release media and public demo.
See the v1 release notes and Phase 7 production validation.
MIT

