A buyer taps Pay, sees an error, and tries again. Your store may now have an unpaid order, a reserved item, and two checkout attempts. If the confirmation page says “order placed” while the payment has not succeeded, the buyer and fulfillment team have different facts. The fix begins with a state test, not another checkout button.
This guide uses Stripe Checkout as a worked example. Stripe says checkout.session.completed occurs when Checkout is completed, while a delayed method can later emit checkout.session.async_payment_succeeded or checkout.session.async_payment_failed. Its fulfillment guide tells integrators to inspect the Checkout Session's payment_status before fulfilling and to fulfill only once per payment. A completed session is therefore not, by itself, the store's universal “ship now” rule. Stripe: fulfill orders
Agree on one visible state for each payment outcome
Before development, fill the last four columns with the behavior your platform and operations team can actually support. “Hold” and “release” below are proposed business decisions, not Stripe stock rules. Test each row in the selected platform's sandbox; a hosted checkout, plugin, and custom order system may map payment events to orders differently.
| Test case | Provider evidence to inspect | Store order and stock acceptance | Buyer message | Merchant action |
|---|---|---|---|---|
| Card is declined before payment completes | Failed attempt and Checkout/PaymentIntent state in the provider test account | Do not mark paid or send to fulfillment. Decide whether an unpaid attempt creates a visible order or only a checkout record; check any stock hold. | Explain that payment did not complete and offer a safe retry route without implying an order is confirmed. | Look for the failed attempt, matching order reference, and any stuck reservation. |
| Checkout ends but a delayed method is still processing | Completed session with payment_status not yet paid; later result event pending |
Keep the order pending and out of the shipment queue. Set a documented reservation limit or exception process for scarce stock. | Say payment is processing; state when the buyer will receive confirmation or what to do if it stays pending. | Monitor pending orders and choose who resolves overdue ones. |
| Delayed payment succeeds | checkout.session.async_payment_succeeded; recheck the session's payment status |
Move the existing order to its paid/fulfillable state once, subject to normal stock and fraud checks. | Send one clear paid-order confirmation, using the actual order reference. | Confirm one fulfillment trigger and one audit trail. |
| Delayed payment fails | checkout.session.async_payment_failed and current payment state |
Keep fulfillment blocked. Apply the store's documented reservation/release rule; do not silently leave stock unavailable. | State that payment failed and how to retry or contact support. | Reconcile the failed attempt and release or review the hold as specified. |
| Buyer retries, or the webhook is delivered again | Two attempts or repeated event IDs for the same Checkout Session | Associate each attempt with the correct order. A repeat delivery must not create a second shipment, license, or confirmation. | Show only the state of the actual successful order; avoid two “paid” emails. | Verify idempotent fulfillment and investigate any duplicate work. |
| Buyer pays but never returns to your success page | Successful provider event; no page visit | The order still reaches the paid/fulfillment workflow. | The confirmation arrives through the configured channel even without a return visit. | Match the provider event to the order and inspect delivery logs. |
Stripe provides sandbox test cards for declines and successful payments. Its payment-method guidance says delayed methods remain processing until a later success or failure and recommends keeping the order pending until success. Use the provider's own test scenarios for the methods you actually offer; do not use live customer card details as test data.
Test the boundary between provider, store, and warehouse
The hardest failures happen between systems. Stripe says the success landing page is insufficient for fulfillment because a buyer may pay and never load it. Its webhook documentation also says events may be retried, duplicated, or arrive out of order. Record processed event IDs, verify webhook signatures, and make fulfillment safe to run more than once for the same Checkout Session. Stripe: fulfillment · Stripe: webhook delivery and duplicate events
For each matrix row, save the provider event or session ID, store order ID, timestamps, customer-visible screen/email, stock before and after, and fulfillment job result. Then deliberately repeat the event and close the browser before the return page. A pass is an aligned record and action, not just a green payment-provider dashboard. If the provider says paid but the store says pending, or the store says paid before the provider does, the launch test has found a reconciliation problem.
This is different from checking that a selected Shopify variant stays the same through the cart or that a product feed and cart show the same price and stock. Those tests establish what the buyer is buying. This test establishes whether and when that order may be fulfilled after payment. It also complements the trust check at an unfamiliar payment screen: trust copy cannot repair a contradictory order state.
Put the decision in the commerce brief
Name the owner of the order-state map, the rule for stock held during a pending payment, the retry path, the support queue, and the evidence required before fulfillment. Define a time-bound manual review for orders that remain pending beyond the chosen method's expected window. Payment methods, stock policies, and platform integrations vary; the matrix is an acceptance brief, not a claim that Stripe or any other provider automatically implements these store behaviors.
ARCHV's website work can include a separate commerce discovery and scope review. Share the current checkout platform, payment methods, order workflow, and one redacted failed attempt through the website estimate. We can then test whether the integration and acceptance cases fit the project before proposing changes.