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.

VE VyaparGateway Engineering Payments Product & Engineering 3 min read
Payment Session Expiry UX Without Duplicate UPI Payments guide
payment session expiry UX expired UPI order duplicate UPI payment prevention checkout timeout design

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:

ConceptOwner
Payment attempt validityPayment contract and backend state
Price validityMerchant commerce policy
Inventory reservationMerchant order system
Customer page timerUser-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.