Skip to content

The checkout worked in the demo. Now test the difficult cases.

Total views 17

One product, one customer, one successful payment. The demonstration ends with a green tick. Production introduces a second click, a lost connection and a payment notification arriving after the browser has closed. The green tick needs a more demanding rehearsal.

A checkout coordinates several systems. The browser, the shop database, the payment provider and the inventory service can disagree temporarily. Design for that disagreement instead of assuming every request finishes once, in order, and while the customer is watching.

Separate payment from the page that says thank you

The browser returning to a success page is not sufficient evidence that an order should be fulfilled. Use the payment provider's documented server-side confirmation process and verify the relevant status, amount, currency and order association.

Keep separate concepts for order, payment attempt, reservation and fulfilment. A payment can succeed while fulfilment is delayed. A failed payment attempt does not necessarily mean the customer has abandoned the order. A single “success” boolean struggles to describe these situations.

A retry must not become another purchase

Suppose the customer presses Pay, the request succeeds, but the response never reaches the browser. Pressing again may be a reasonable human action. The system must decide whether it is continuing the same operation or starting a different one.

Stripe documents idempotency keys for safely retrying supported requests. Use a stable identifier for the same intended operation and respect the provider's parameter and retention rules. This does not automatically make your own database writes, emails or stock movements idempotent.

Define a local operation identifier and enforce the corresponding uniqueness where needed. Marking a notification as processed and applying its business change should be coordinated so that a crash cannot leave the change applied but the event ready to run again.

Notifications can be late, repeated or out of order

Stripe's webhook documentation explicitly describes duplicate deliveries and does not guarantee event ordering. Verify signatures using the documented method, preserve the required raw request body and fetch authoritative state when necessary. Avoid treating arrival order as the history of the business.

A practical example: an old notification arrives after a refund has already been recorded. Blindly setting the order to “paid” can overwrite a newer state. The handler needs valid transitions and a reconciliation strategy, not just a switch statement that trusts the last message received.

Acknowledge notifications promptly after reliable receipt and move slow work to an appropriate background process. Monitor failures and retries. A queue that nobody checks can turn a recoverable integration error into an invisible backlog.

Stock and refunds deserve their own tests

Test two customers competing for the last unit. Decide what happens if a reservation expires before payment confirmation. Define how operators handle a successful payment when the item cannot be supplied. Do not silently invent inventory or leave an unexplained charge.

Refunds are operations too. Distinguish a refund request from a confirmed result, and consider partial refunds, retries and failure messages. Returning money does not automatically mean a physical item is ready to sell again; inspection and inventory policy may be separate steps.

A rehearsal worth running

  • Double click Pay and repeat the same request after a simulated timeout.
  • Close the browser before server-side confirmation arrives.
  • Deliver the same test webhook twice and deliver relevant events out of order.
  • Interrupt processing between recording an event and applying its business effect.
  • Expire the final stock reservation before a late payment confirmation.
  • Request a partial refund, repeat the request and simulate a provider failure.
  • Disable an integration temporarily, restore it and reconcile missed work.

Use sandbox credentials and synthetic data. For every case, record the expected customer message, payment state, inventory movement and operator action. “No exception in the logs” is not an acceptance criterion if the customer paid twice.

Design the recovery screen too

Give support staff enough traceability to connect an order to its payment attempts and notifications without exposing unnecessary sensitive data. Provide controlled retry or reconciliation actions with an audit trail. Direct database edits should not be the routine checkout workflow.

A reliable checkout is not one where nothing ever fails. It is one where failure does not quietly duplicate a charge, lose an order or leave the customer guessing.

Sources

Stripe: webhook handling; Stripe: idempotent requests. Consulted 17 October 2026. Stripe is an implementation example; other providers have their own contracts. The scenarios are proposed tests, not results from a production payment experiment.

Categories

Software products