NOETRION

Choose a topic

FINTECH · 6 MIN READ

The Payment Webhook Arrived Twice. Your Customer Should Still Receive One Order.

Separate webhook delivery from business effects, handle duplicates and out-of-order events, and plan reconciliation without assuming exactly-once processing.

Educational analysis, not a personal investment or payment recommendation. Check the dated sources and the rules that apply in your jurisdiction.

A payment succeeds, your server prepares an order, and the response to the payment provider is lost. The provider sends the notification again. If the application treats every delivery as a fresh instruction to ship, a communication retry can become a second parcel.

The problem is not solved by hoping that the network delivers each message once. Design the business effect so that repeated evidence of the same event does not repeat the same action. Then separately handle the cases where different events refer to the same business object or arrive in an unexpected order.

Stripe's webhook documentation, checked on 25 October 2026, says deliveries can repeat and event order is not guaranteed. It recommends duplicate handling and signature verification. This article uses those documented behaviors as context for an original design worksheet. It is not a production integration or a universal description of every payment provider.

An original four-delivery sequence contains event E1 twice, a different event E2 for the same paid invoice, and event E3 for another invoice; three unique event IDs correspond to only two distinct invoice fulfilment effects.
Original explanatory diagram. Delivery count, event count and authorized fulfilment count describe different things in this fictional workflow. Open full-size diagram.

Separate three identities

A delivery is an attempt to send a notification. An event has a provider-assigned identity. A business effect, such as fulfilling an invoice, has an application-defined identity and authorization rule.

The same event can be delivered repeatedly. Different events can also concern the same invoice or payment. Recording only the delivery count cannot establish how many distinct business actions are appropriate.

Use identifiers with their account and environment context. A test-mode object should not activate a live order, and an identifier from one tenant should not match another tenant's fulfilment record merely because a string looks similar.

Verify the notification before trusting it

A JSON body claiming that a payment succeeded is not enough. Apply the provider's documented authenticity verification to the raw request in the expected environment, and use the appropriate signing secret and library behavior.

Then check that the event belongs to the account and object your application is authorized to process. An authentic event can still be irrelevant to this order or require a state lookup before action.

The worksheet below begins after those checks. It does not supply signature-verification code, substitute for the provider's current integration guide, or authorize handling real money during a test.

Work through a duplicate example

Consider four original deliveries. Invoice I1 and invoice I2 are distinct valid orders in the same fictional account. The team has already defined the permitted fulfilment transition for a paid invoice.

Delivery Event identity Business object Intended effect
1 E1 Paid invoice I1 Create I1 fulfilment once
2 E1 again Paid invoice I1 No second fulfilment
3 E2 Same paid invoice I1 Inspect transition; no second fulfilment
4 E3 Paid invoice I2 Create I2 fulfilment once

There are four deliveries, three unique event identities and two distinct fulfilment effects. The third row is why remembering event IDs alone is insufficient for this business rule. It is a separate event but not permission for a second shipment.

Do not generalize “one effect per object” to every workflow. A legitimate refund, installment or partial shipment can require additional actions. Define the effect key from the actual business transition.

Make the local state transition indivisible

A fragile handler checks whether an effect exists, sees none, then creates it. Two simultaneous handlers can both pass that check. A durable uniqueness rule and a transaction can make the intended local transition enforceable.

For this original design, the transaction records the verified event, checks the invoice transition, and creates one pending fulfilment job under a unique effect key. If the local transaction fails, its partial state must not be reported as successful business processing.

The exact database design depends on the application. A uniqueness constraint is useful evidence of the rule, but it does not validate the payment, solve every race, or atomically coordinate an unrelated external shipping API.

Keep external actions outside false transaction claims

A database commit cannot roll back a parcel already accepted by another company's system. If the worker calls shipping and loses the response, it may not know whether the action succeeded.

Use the destination's supported idempotency or conditional-operation mechanism where available, tied to the same intended effect. Preserve the request reference and reconcile an ambiguous result rather than issuing a new unrelated action blindly.

Stripe's API idempotency reference concerns retries of API operations. That is a different boundary from incoming webhook deduplication. An outgoing idempotency key does not automatically protect the application's own inventory, ledger or shipping workflow.

Accept durable work before acknowledging it

An HTTP success response and completed fulfilment are different milestones. If the architecture acknowledges after durable acceptance into a queue or transactional job record, the background worker can finish later under the application's recovery policy.

The acceptance must actually survive the failure being considered. Placing an item only in process memory, acknowledging, and then crashing can lose the job even though the provider believes delivery succeeded.

Boundary Evidence to retain Failure to exercise
Verified receipt Event ID, account, verification result Invalid or wrong-environment message
Durable local acceptance Committed event and effect/job record Crash before acknowledgement
External action Stable effect reference and response Response lost after acceptance
Business completion Reconciled destination state Job left ambiguous or pending

A quick acknowledgement is useful only when its meaning matches the durability the system actually provides.

Handle order without rewriting history blindly

A delayed earlier notification may arrive after a later state. Do not assume arrival order defines the current business state. Retrieve missing or current provider objects as appropriate and apply documented transition rules.

For example, an old “created” notification should not mechanically move a locally fulfilled invoice back to an initial state. Preserve the event for traceability while deciding whether it changes the current state at all.

A timestamp is not automatically a total ordering key. Distinct events may share a timestamp, and different object types can represent different workflows. Select the rule for the provider's actual event model rather than inventing a generic latest-number-wins system.

Test the ambiguous outcomes

In an authorized test environment, resend the same event, submit two deliveries concurrently, and deliver related events in a different order. Inject a failure before the local commit and another after durable acceptance but before the response is received.

Also test the external worker's uncertain-result path. Can an operator identify the intended effect and confirm whether it occurred without repeating it? A dashboard that shows only retry counts may not answer that question.

Record expected business outcomes before running the tests. “No exception occurred” is not sufficient when the failure you care about is a duplicated shipment or an order that never leaves the queue.

Reconcile effects, not just messages

Review pending and ambiguous jobs against payment and destination evidence. Give each exception an owner and a next action. Retain enough identifiers to distinguish a repeated delivery from a new legitimate business transition.

The useful guarantee is specific: within the stated local transaction and destination contracts, the system prevents repeating a defined effect and can investigate uncertainty. Calling the whole integration “exactly once” without those boundaries hides the work that makes a retry safe for the customer.

Sources and further reading