DEV Community

Dipendra Neupane
Dipendra Neupane

Posted on

Webhooks Aren't Notifications. They're Distributed Systems.

Here are a few lessons I learned while working with Stripe Webhooks in production.

āš”š—¬š—¼š˜‚š—æ š—›š—§š—§š—£ š˜€š˜š—®š˜š˜‚š˜€ š—°š—¼š—±š—² š—¶š˜€ š˜†š—¼š˜‚š—æ š—æš—²š˜š—æš˜† š—½š—¼š—¹š—¶š—°š˜†.

Returning 200 tells Stripe the event was received and processed successfully. Stripe won't retry it again.

If your business logic fails, you should return a 5xx status code so that Stripe automatically retries the event delivery

āš”š—§š—µš—² š—²š˜ƒš—²š—»š˜ š˜†š—¼š˜‚ š—æš—²š—°š—²š—¶š˜ƒš—² š—¶š˜€ š—® š—µš—¶š—»š˜, š—»š—¼š˜ š˜š—µš—² š˜š—æš˜‚š˜š—µ.

Webhook events may arrive late or out of order. Don't trust the payload. Refetch the current state from a source of truth and act accordingly.

āš”š——š—¼š—»'š˜ š—±š—¼ š˜€š—¹š—¼š˜„ š˜„š—¼š—æš—ø š—¶š—»š˜€š—¶š—±š—² š˜š—µš—² š—Ŗš—²š—Æš—µš—¼š—¼š—ø š—²š˜ƒš—²š—»š˜.

Stripe has a timeout threshold. If the endpoint doesn't respond quickly enough, Stripe considers it a failure and retries.

Process the slow work asynchronously outside the webhook handler.

Do you have any hard-learned lessons about Webhooks or Stripe? I'd love to know about that.

I share more engineering notes and production lessons on LinkedIn: Dipendra Neupane.

Top comments (3)

Collapse
 
challan116ux profile image
challan116-ux •

Strong framing. In B2B EDI over AS2 we live this same problem wearing older clothes: when a functional acknowledgment (or MDN) goes missing, the sender can't tell whether the document processed or just vanished — so both sides need explicit acknowledgment semantics beyond the HTTP status. Separating ack from processing is the only approach that has ever actually worked for us.

Collapse
 
muhammad_turnergane_7ddc profile image
Muhammad Turner Gane •

good list. one i learned the hard way: returning 5xx is only safe if the retry can't double-apply. if the handler wrote half the access change before it threw, the retry runs on top of that. we record the event id in the same transaction as the access change, so a retry finds either nothing done or everything done. also worth testing what happens when stripe's retries run out, because after that nothing tells you again.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.