Treat delivery as a message, not a command
Stripe documents that webhook events can be delivered more than once and that delivery order is not guaranteed.[2] This is a documented property of Stripe, not a promise about the exact retry schedule of another provider. The general design recommendation is still useful: receiving a message must not directly mean shipping an order or crediting an account. First establish authenticity, record the event and decide whether its business effect has already happened.
Verify before accepting work
Stripe requires the raw request body for signature verification and recommends its official libraries.[2] Use the signing method documented by your own provider; do not invent a generic header or reuse a Stripe implementation for PayIn. Reject invalid signatures and keep signing secrets on the server. Separate sandbox and production configuration. A valid signature demonstrates the origin and integrity of a message under that scheme; it does not prove that fulfillment remains appropriate for your current order state.
Persist before acknowledging success
Stripe recommends asynchronous processing and a quick successful response rather than doing complex work inside the HTTP request.[2] Our proposed architecture is a verified event intake, durable inbox or queue and a worker that performs a guarded state transition. Acknowledge after durable acceptance, not after merely starting an in-memory task. Make the event record and intended business transition transactional where possible. If the worker crashes, it should be safe to retry without issuing the same stock release or customer credit again.
Deduplicate both messages and effects
Stripe recommends tracking processed event IDs and notes that distinct event objects can sometimes represent the same object and event type.[2] Keep provider event identity separate from your business idempotency key. As an example design, the fulfillment key might identify an order and a particular fulfillment action; it is not automatically the blockchain hash alone, because one transaction can require more precise event identification. Use a database uniqueness constraint or equivalent atomic guard. This is architectural guidance, not production-ready code.
Recover without relying on perfect delivery
PayIn identifies successful webhook delivery followed by failed internal fulfillment, and duplicated processing, as reconciliation cases.[7] Build a review path that compares authoritative payment records with internal results. Suggested tests include repeated delivery, reversed event order, an invalid signature, a worker crash and a missing notification. Preserve the payload reference, decision and resulting ledger or fulfillment ID. Do not claim an order is fixed merely because an HTTP endpoint returned 200; verify the intended business effect and its uniqueness.
Sources & currency
Continue reading
Visible onchain is not the same as ready to fulfill →
All field guides →