Payment, auth and email providers tell your app what happened through webhooks. They arrive late, twice, out of order or not at all, and anyone can send a fake one. Using Stripe's documented behaviour as the example, the handler pattern that survives all of it.
A webhook is an HTTP POST from another company's servers to yours. If it is the only way you learn that a subscription renewed or a payment failed, its delivery guarantees become your app's. They are weaker than most people assume.
Undelivered events are retried for up to three days with exponential backoff in live mode; sandbox events three times over a few hours.
Order is not guaranteed: invoice.paid can arrive before invoice.created.
The same event can arrive more than once, and occasionally two different events describe one change.
Your endpoint must return 2xx quickly, before slow work. Redirects count as failures.
Each event carries an HMAC-SHA256 signature with a timestamp; the libraries reject events older than 5 minutes by default. Verification needs the raw body exactly as received.
Other providers differ in detail, rarely in kind. Assume these properties unless a provider's documentation says otherwise.
Book a free 30-minute call. You'll leave knowing what we'd do first and roughly what it costs, whether or not you hire us.
Verify the signature against the raw body and reject failures. Without this, anyone who finds the URL can mark orders paid.
Store the event under a unique constraint on its ID. A conflict means a duplicate: return 200 and stop.
Return 200.
Process from a queue or background worker, so a burst (every subscription renewing on the 1st) does not swamp the web server.
Treat the event as a prompt, not the truth: fetch the object's current state from the provider's API before acting. Order stops mattering.
Run a reconciliation job that lists recent objects from the provider and repairs anything a missed webhook left wrong.
A JSON body parser runs before the webhook route, verification always fails, and someone "fixes" it by turning verification off.
All the work happens before the response, the request times out, and the provider retries a half-processed event.
Access is granted on the checkout redirect rather than from the webhook, so a closed tab means paying without access.
Nobody is alerted when the provider disables the endpoint after repeated failures.
Once a month: what changed in tech that month and what it means for you, from cloud and AI to security and the tools you build with. Every item links to its source. No sales pitch, unsubscribe in one click.
Book a free 30-minute call about it. Bring your setup and your bill; you'll leave knowing what we'd do first and roughly what it costs, whether or not you hire us.
Or keep reading
Timeouts, Retries and Idempotency: The HTTP Habits That Stop Double Charges
Every network call ends in success, failure or "we don't know". The third causes duplicate orders, double charges and stuck jobs. How status codes, timeouts, retries with backoff and idempotency keys fit together, with the limits on API Gateway and Lambda.
Read
What 99.9% Uptime Means, and Why Your App Is Less Available Than Any of Its Parts
Each extra nine is ten times less downtime and usually far more than ten times the cost. Downtime budgets per month, why chaining services multiplies their failures, what an SLA actually promises, and the five checks a small team should have running.
Read
As of October 26, 2026. Provided as is, for general information, and accurate to the best of our knowledge on the date shown. Not legal, compliance, tax, financial or other professional advice. Prices, limits and vendor services change; check current vendor documentation before relying on anything here. Terms of use.