A deliberately unreliable webhook receiver plus a few scripts that drive Svix through every failure mode you would otherwise have to handle yourself: outages, 429s with Retry-After, timeouts, dead endpoints, signature verification, and replay.
Companion to the DevOps Daily article Stop Building Webhook Retries Yourself.
receiver/server.js: a Node HTTP server with one path per failure mode. Every request is recorded and exposed atGET /attempts./okaccepts everything, and deduplicates onsvix-id: a redelivered message is acknowledged but not processed twice/flakyreturns 500 for the first two attempts of each message, then 200/ratelimitedreturns 429 withRetry-After: 60on the first attempt, then 200/slowholds the first attempt open for two minutes (past the sender's timeout), then answers normally/deadalways returns 503- every path verifies the
svix-signatureheader with the endpoint's secret and answers 401 on a bad signature
sender/setup.js: creates the Svix application and one endpoint per path, prints the endpoint secretssender/send.js: sends one message with a uniqueeventIdand anidempotencyKey(reusing the sameeventIdis rejected by Svix; reusing the key returns the original message)sender/report.js: lists every delivery attempt Svix made, per endpoint, with status and timingsender/replay.js: resends one message to one endpoint, or recovers every failed message for an endpoint since a timestamp
You need a Svix API key (free tier is fine) and a public HTTPS URL for the receiver. Svix refuses plain-HTTP endpoint URLs, so the easiest path on a fresh VM is Caddy with automatic TLS on an sslip.io hostname (203-0-113-10.sslip.io resolves to 203.0.113.10).
npm install
# 1. create the app and endpoints (prints ENDPOINT_SECRETS for step 2)
SVIX_API_KEY=... PUBLIC_URL=https://203-0-113-10.sslip.io npm run setup
# 2. start the receiver (behind Caddy or any TLS terminator on :443 -> :8080)
ENDPOINT_SECRETS='{"/ok":"whsec_...","/flaky":"whsec_...",...}' npm run receiver
# 3. send a message; every endpoint receives it
SVIX_API_KEY=... npm run send
# 4. watch the retries land over the next half hour
SVIX_API_KEY=... npm run report -- msg_xxx
curl -s https://203-0-113-10.sslip.io/attempts
# 5. replay
SVIX_API_KEY=... node sender/replay.js resend /dead msg_xxx
SVIX_API_KEY=... node sender/replay.js recover /dead 2026-09-01T18:00:00ZA Caddyfile for the TLS front is two lines:
203-0-113-10.sslip.io {
reverse_proxy receiver:8080
}
Recorded output from a real run is in RESULTS.md.
MIT licensed.