A webhook handler looks like twenty lines until it meets production. Then the same Stripe event arrives twice, your database blips during a deploy, a forged request hits the endpoint, or a worker is killed halfway through fulfilling an order. Reliable Webhooks is the part you would otherwise design, write and test yourself: verify, store, acknowledge, process, retry, and dead-letter.
The failure cases it handles
| What happens | What the kit does |
|---|---|
| Request with a bad or missing signature | 401, nothing stored, logged without the payload |
| Captured request replayed later | Rejected by timestamp tolerance (and by idempotency) |
| Same event delivered twice, or ten times concurrently | Handler runs once; the database decides the winner |
| Your database is down when the webhook arrives | 500 so the provider retries, because nothing was stored |
| Your handler throws | Event is stored, acknowledged and retried with backoff and jitter |
| Worker killed mid-handler (deploys, serverless timeouts) | Lease expires, event is re-claimed. A poison event is dead-lettered, not looped |
| An event can never succeed | NonRetryableError sends it straight to dead letters; replay() revives it after you fix the cause |
How it looks
const receiver = createWebhookReceiver({
provider: stripeProvider({ secret: process.env.STRIPE_WEBHOOK_SECRET! }),
store: new PostgresStore(pool),
handlers: {
"checkout.session.completed": async ({ event, idempotencyKey }) => {
await grantAccess(event.payload, idempotencyKey); // runs once per event
},
},
});
// app/api/webhooks/stripe/route.ts
export const POST = (request: Request) => receiver.handle(request);
// cron, every minute
await receiver.processDue();
What's in the package
src/ ~780 lines of strict TypeScript, zero runtime dependencies
migrations/ one idempotent SQL file
tests/ 60 tests: providers, receiver, retries, Node adapter, store contract (Memory + Postgres)
examples/ offline demo (npm run demo), Next.js route + cron worker, node:http / Express
docs/ ARCHITECTURE.md (lifecycle and why), SECURITY.md (threat model, deployment checklist)
README.md CHANGELOG.md LICENSE.md
The test suite includes concurrency tests against a real PostgreSQL database and a contract suite you can run against your own store implementation. You can run npm run demo the moment you unzip it to watch a forged request, a duplicate, an outage and a recovery play out against a real HTTP server.
Who it is for
Teams on Node and TypeScript who take payments, sync with GitHub or receive webhooks from any HMAC-signing service, and want it to be correct without building a queue system.
Who it is not for
- Sending webhooks to your own customers (this is the receiving side).
- Very high volume pipelines: events are processed through PostgreSQL, which is comfortable for typical SaaS traffic but not a replacement for Kafka-scale ingestion.
- Non-JavaScript runtimes.
- Exactly-once side effects: no webhook system can promise that. The kit gives you at-least-once delivery plus an idempotency key per event so your handler can be made safe.
What you get
- Signature verification for Stripe, GitHub and any HMAC-SHA256 scheme: constant-time, timestamp tolerance, secret rotation
- Idempotency enforced by the database: duplicates and concurrent deliveries run your handler once
- Durable storage first, then 2xx: you own delivery from the moment an event is stored
- Retries with exponential backoff and full jitter, handler timeouts, dead letters and replay
- Crash recovery with leases: events held by a killed worker are re-claimed, poison events are dead-lettered
- PostgreSQL store (FOR UPDATE SKIP LOCKED) with migration, plus an in-memory store and a store contract test suite for other databases
- Structured logging that never records payloads, headers or secrets
- Next.js route handler, cron worker and node:http / Express adapters
- 60 automated tests (10 run against a real PostgreSQL), runnable offline demo, architecture and security docs, changelog
Will it work in my project?
- Node.js 20 or newer (tested on 20, 22, 24 and 26)
- PostgreSQL 12+ for the included store (any database via the WebhookStore interface)
- Something that can call processDue() on a schedule (cron, Vercel Cron, a timer)
- TypeScript 5+ recommended; zero runtime dependencies
What happens after you buy
- Pay on Stripe. You need a Softreuse account (free, email confirmation). Card details go to Stripe, never to us.
- Access is granted automatically as soon as Stripe confirms the payment, usually within seconds. Stripe emails the receipt.
- Download from your account at any time: the .zip, its SHA-256 checksum, and the full documentation. Links are generated on demand, so you can come back in a year.
- Unzip,
npm install,npm test,npm run demoto see it work before you touch your own code. - Updates: every v1.x release appears in the same place, free.
Not working as documented? Full refund within 14 days. Questions before buying: support@softreuse.com.
Security
The security design is documented in the package (docs/SECURITY.md) with a threat model. In short:
- Authenticity: HMAC-SHA256 over the raw body using Web Crypto's constant-time
verify; every candidate secret is checked without early exit; malformed headers always end in401, never an unhandled exception. - Replay: timestamp tolerance where the provider sends one (Stripe default 300 s); idempotency on the delivery id everywhere.
- Abuse: request body capped (default 1 MiB) both by
Content-Lengthand while streaming. - Injection: all SQL values are bound parameters; the one interpolated identifier (table name) is validated; a test stores hostile payload text.
- Privacy: logs contain ids, event types and attempt numbers only. No payloads, headers or secrets. This is tested.
- Supply chain: zero runtime dependencies;
npm audit --omit=devis clean. - Honest limits: no IP allow-listing, no ordering guarantees, no encryption at rest (your database's job), at-least-once delivery. These are documented along with a deployment checklist.
Versions & changelog
v1.0.0 · Oct 8, 2026
Initial release.
createWebhookReceiver: verify → persist → acknowledge → process, withinlineanddeferredmodes.- Providers: Stripe (
stripeProvider), GitHub (githubProvider) and a generic HMAC-SHA256 provider (hmacProvider) with timestamp tolerance, hex/base64 encodings and secret rotation. - Idempotency on
(provider, event id), enforced by the store (primary key in Postgres). - Retries with exponential backoff and full jitter, lease-based crash recovery, dead-lettering,
NonRetryableError, handler timeouts andreplay. - Stores:
PostgresStore(FOR UPDATE SKIP LOCKEDleasing) andMemoryStore(tests/demo), plus a publicWebhookStoreinterface. toNodeHandleradapter fornode:http/ Express; Web-standardhandle(Request)for Next.js, Hono, Bun, Deno, Workers.- 60 automated tests including a store contract suite, concurrency and crash-recovery cases.
License
Softreuse Commercial License — Reliable Webhooks
Version 1.0 · Copyright © Softreuse. All rights reserved.
This is the license that comes with your purchase of this package ("the Software"). Please read it; it is short on purpose.
1. What you may do
You (the individual or single company that purchased the Software, "Licensee") may, forever, for the versions covered by Section 4:
- use, copy and modify the source code in any number of projects that you or your company own or build for your own use, commercial or not;
- let your employees and contractors work with the source for those projects;
- ship products that contain or are built from the Software (including compiled or bundled) to your own users and customers;
- keep your modifications private.
2. What you may not do
- Redistribute, resell, sublicense, publish or share the Software's source code, in original or modified form, as a standalone product, template, boilerplate, starter kit, library, SaaS feature-for-feature clone, course material or marketplace listing.
- Publish the Software's source in a public repository or package registry. (Private repositories of your team are fine. Publishing an application that merely uses the Software is fine.)
- Share your download access or purchase with people outside your company.
- Remove copyright or license notices from the files.
If you are a consultancy building a product for a client, the client needs their own license unless the client is the owner of the resulting project and you transfer the project (not the Software as a standalone asset).
3. Ownership
Softreuse keeps ownership of the Software. You own everything you build with it.
4. Updates
Your purchase includes all releases of this product within the major version you bought (for example every 1.x release if you bought 1.0.0), delivered through your Softreuse account. A new major version (2.0.0) is a new paid release; versions you already have keep working under this license forever.
5. Warranty and liability
The Software is provided "as is", without warranty of any kind. Softreuse tests the Software and publishes known limitations, but you are responsible for evaluating it for your use, including security review of your own deployment. To the maximum extent permitted by law, Softreuse's total liability for any claim is limited to the amount you paid for the Software, and Softreuse is not liable for indirect or consequential damages (lost profits, lost data, business interruption).
6. Refunds
If the Software does not work as documented, tell us within 14 days of purchase and we will refund you in full. Refunded licenses end at the moment of refund.
7. Termination
This license ends automatically if you breach Section 2. Sections 3, 5 and 7 survive termination.
8. Contact
Questions
Why not just ask an AI to write this?
You can, and for many things you should. The hard part of webhooks isn't the first draft, it's the cases nobody prompts for: the same event arriving ten times at once, a worker killed mid-handler, a database outage during delivery. This package comes with tests for those cases, run against a real PostgreSQL database, plus a written threat model. You still review the code. You just start from something that has already been tested against production failure modes.
What exactly do I get after paying?
A .zip with the full TypeScript source, tests, runnable examples, SQL migration, architecture and security docs, a changelog and the licence. It's available in your Softreuse account the moment Stripe confirms payment, and you can download it again any time.
What does the licence allow?
Use it in unlimited projects you or your company own, commercial or not, and modify it freely. You can't resell or redistribute it as a standalone product or library. The full text is on the product page and inside the package.
Which versions does my purchase cover?
Every release of the major version you bought. Buy v1 and you get all v1.x updates (fixes and backwards-compatible features) for free. A future v2 with breaking changes would be a separate paid release; v1 stays yours either way.
Will it work with my stack?
It targets Node.js 20 or newer, TypeScript, and PostgreSQL for the included store. It has zero runtime dependencies and uses Web-standard Request/Response, so it also works in Next.js route handlers, Hono, Bun and Deno. Any other database works by implementing a small store interface that ships with a contract test suite. It is not for sending webhooks, and not for non-JavaScript runtimes.
What if it doesn't work for me?
Email support@softreuse.com. If it doesn't work as documented and we can't fix it, you get a full refund within 14 days of purchase. No forms, no hoops.
Is checkout secure? Do you see my card?
Payment happens on Stripe's hosted checkout page. Your card details never touch Softreuse servers. Access is granted only after Stripe confirms the payment to us by a signed server-to-server message.
Do you charge VAT or sales tax?
Taxes are added at checkout where required. Stripe sends a receipt, and an invoice with your company name or VAT number is available on request.