A customer approves a stablecoin payment on one chain, puts their phone away and comes back to an unpaid order. The wallet has a transaction hash. The store has no delivery receipt. Should the customer try again?
A checkout that cannot answer that question is not ready to add another chain. The hard part is keeping the customer's next action correct while the route, the destination payment and the order each have different information.
Give the order and the payment attempt different lives
An order describes what the merchant is selling and how much it expects to receive. An attempt describes one way of paying: source chain and asset, destination chain and asset, expected recipient, quoted amount and route identifier. An order can survive a rejected signature or an expired quote. An attempt that already moved funds needs a different recovery path.
When a quote expires before signing, let the user get a fresh quote. Once a source payment has been submitted, reopening checkout should restore the existing attempt. If submission itself is uncertain, reconcile it before offering a replacement. Never ask for another signature just because the browser lost its place.
Make “paid” a merchant decision
A source receipt proves something happened on the source chain. It does not prove that the merchant was paid. Cross-chain routing can fail on the destination; Relay’s documentation describes it as a separate failure case.
The merchant should fulfill from its own recorded decision, based on evidence that matches the order. Check the destination network, token contract, recipient and amount, under a defined confirmation policy. If the route reports success but the destination details differ, keep it in review rather than fulfilling or presenting a generic “try again.”
Make the fulfillment decision durable and guard it atomically. A callback retry, an indexer backfill and a customer refreshing the receipt can all observe the same outcome. Only one should cause fulfillment.
Explain where the money is
Give support the order ID, route ID, transaction evidence and last verified state. Keep customer copy short: “Payment submitted,” “Still moving,” “Refund pending,” or “Refund confirmed.” A refund estimate is different from a confirmed receipt. Even after a refund, opening a new attempt should be a deliberate action.
The frontend explains the state. A production integration needs a durable backend that can reconstruct it after a device, callback or RPC failure.
Try Checkout Recovery Lab
Run the destination failure case. The source receipt is visible, but checkout remains unpaid; only confirmed refund evidence permits a new attempt in this case. Then replay a successful settlement to see why only one delivery is recorded. The lab uses fictional receipts; it does not sign, bridge, issue refunds or move money.
What dOrg would build first: one route into one existing checkout, with a resumable receipt, an operator view for exceptions and acceptance tests for duplicate delivery, destination failure and refunds. Bring the source assets, settlement network and order API.

