A Stripe integration can pass every test-mode check and still go wrong with real customers. The reason is simple: in production Stripe may send the same event more than once, in any order, and it keeps retrying when your endpoint is slow or down. This short shows a basic handler and a hardened one getting the same traffic:
If you only change four things in your handler this week, make it these:
-
Verify first, using the raw body. Check the
Stripe-Signatureheader against the exact bytes Stripe sent. Parsing the JSON and re-serialising it breaks the signature. -
Remember every event you've handled. Insert
event.idinto a table with a unique key before doing any work. If the insert fails because the id already exists, it's a repeat delivery: return 200 and stop. - Answer fast, work later. Save the event and return 200 within a second or two, then let a background job update the database and send emails. Slow handlers cause timeouts, timeouts cause retries, and retries pile up during a launch.
-
Don't trust arrival order. When a subscription event arrives, re-read the subscription from Stripe (or compare the event's
createdtime with what you stored) before overwriting the user's plan.
The full write-up, with diagrams and code for each failure, is here: 7 ways Stripe webhooks break in production. There's also a free Stripe webhooks go-live checklist.
Disclosure: the clip is for Webhook-Proof Stripe, a paid billing kit for Next.js and FastAPI from Syncoders Labs (us). Details are on its site.
Top comments (0)