growth
Payment Session Expiry UX Without Duplicate UPI Payments
Explain checkout expiry accurately, stop unsafe retries, preserve order identity, handle late payment success, and give customers a clear recovery path.
Expiry is often treated as a visual countdown, but it is a payment-state decision. The page must explain whether the QR, Intent, price reservation, inventory hold, or checkout attempt expired—and what the backend will do if authenticated payment evidence arrives later.
An arbitrary timer that only hides the QR does not make the original payment impossible.
Define What Actually Expires
Document four separate concepts:
| Concept | Owner |
|---|---|
| Payment attempt validity | Payment contract and backend state |
| Price validity | Merchant commerce policy |
| Inventory reservation | Merchant order system |
| Customer page timer | User-interface representation |
Do not display a validity duration unless the backend can enforce and explain it. The UI must read the server-owned expiry timestamp rather than starting a new local countdown on every reload.
Store the order reference, expected amount, created time, expiry time, and state before presenting payment. Use a synchronized server clock for decisions.
Design the Expiry Warning
Show the exact time remaining in a human-readable form and warn before the attempt ends. The warning should say what will happen: “This checkout attempt will close. If you already paid, do not pay again while we verify the result.”
Avoid threats such as “your money will be lost.” Give customers enough time to switch to a payer app or scan from another device. Respect accessibility needs; do not make the timer the only indication of expiry and do not announce every second to screen readers.
When the visible timer reaches zero, request the current server state before changing the page.
Close the Attempt on the Server
Use an idempotent backend transition from pending to expired only when allowed by the state machine. A final paid state must never be downgraded by a late expiry job or stale browser request.
Stop accepting new customer actions against the closed attempt, but preserve its references for reconciliation. Do not delete the order or reuse its client_txn_id. If a new attempt is needed, create a separate reference linked to the original purchase.
The expired-order recovery guide explains the backend policy and audit record.
Handle Late Success
Authenticated success can arrive after the merchant’s local window. Route it to one explicit policy:
- Honour the original order when inventory and price remain valid.
- Hold for merchant review.
- Start the authorized refund or grievance process.
- Contact the customer before fulfilment when the commercial context changed.
Record original expiry, payment verification time, evidence ID, decision, actor, and customer communication. Never auto-mark a late payment failed merely because the page timer ended.
Offer a Safe Retry
Show a new payment action only after the backend establishes that the original attempt is closed and no successful payment is known. Label the replacement clearly and keep the original support reference visible.
Before a new attempt, revalidate price, inventory, merchant connection, and customer intent. If the original remains under review, provide a support case and tell the customer not to pay again.
Test reload at the expiry boundary, two open tabs, a slow payer-app return, status arriving after expiry, concurrent expiry and success events, and a retry started from another device. The passing result is one final commercial decision and no duplicate fulfilment.
Give operations an expiry exception view containing original order reference, expected amount, expiry timestamp, verified evidence time, replacement attempt, and resulting commercial decision. Group a replacement and original together so support does not fulfil both independently.
Track expiry rate, payment verified shortly after expiry, replacements created, duplicate-payment cases, and customers contacting support from an expired page. A high expiry rate can indicate an unrealistic validity window, slow customer journey, unclear instructions, or delayed verification. Do not solve it by extending only the visible timer while the backend still closes the attempt earlier.
Review the expiry policy with inventory, customer support, finance, and engineering. Each team must use the same definition of late payment and the same authorized resolution path.
Direct answers
Frequently asked questions
- Does an expired checkout mean a payment definitely failed?
- No. It means the local payment attempt or offer window ended. Authenticated payment evidence can still arrive late and must be handled by policy.
- Should the page create a replacement order immediately at zero?
- No. First resolve or formally close the original attempt through the backend. Creating a replacement while the first result is unknown can cause duplicate payment.
- What should the customer see after expiry?
- Show what expired, whether payment is still being checked, the original order reference, and the exact safe action: wait, review status, contact support, or create a new attempt.
Build your payment flow
Explore the API and browser-only merchant tools.
Create UPI checkout orders, verify signed events, or test the free calculators and generators without exposing credentials.