Payment status verification is a recovery and reconciliation mechanism. It is useful when the customer closes the page, your create-order response times out, or a webhook delivery is delayed. It must run from your backend because it uses your API key and influences fulfilment.
Treat the response as evidence about a known local order. Locate the order with order_id or client_txn_id, then validate the amount and allowed state transition. A successful response for an unknown or mismatched reference should be held for investigation rather than auto-fulfilled.
Design principles
The boundaries that keep this flow reliable
Query known orders only
A status worker starts with a stored local order and expected amount. It does not scan arbitrary references or use customer-submitted IDs without authorization.
Use a state machine
Allow pending to become paid, expired, or failed. Never let a later stale response downgrade a final paid order.
Bound the retry window
Use backoff and stop frequent checks after a defined period. Move overdue cases into periodic reconciliation instead of permanent rapid requests.
Implementation workflow
From request to a durable result
- 1
Select an unresolved order
Choose a payment_pending order whose next verification time has arrived and lock it against concurrent workers.
- 2
Call check_order_status
Send either the gateway order_id or your original client_txn_id with X-API-Key from the backend.
- 3
Validate immutable fields
Compare tenant, local reference, expected INR amount, and the current state before accepting a status transition.
- 4
Commit then fulfil
Persist the final state and an audit record in one transaction. Queue email, inventory, or access fulfilment only after that commit.
Check status without exposing credentials
tsconst response = await fetch(
"https://vyapargateway.com/api/v1/check_order_status",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.VYAPARGATEWAY_API_KEY!,
},
body: JSON.stringify({ client_txn_id: order.paymentReference }),
},
);
const result = await response.json();
if (!response.ok) throw new Error("Status remains unknown");
// Compare reference, amount and current local state before updating. Production checklist
Verify before going live
- Status endpoint is called server-to-server
- Worker uses exponential backoff with jitter
- Paid is a terminal state and cannot be downgraded
- Unknown and mismatched results enter manual review
- Fulfilment starts after the payment state transaction commits
Failure recovery
Status verification traps
Excessive status checks
Checking every second creates load without improving correctness. Use a short customer-facing window, then back off into scheduled reconciliation.
Redirect treated as success
A browser redirect is navigation, not authenticated payment evidence. Keep the order pending until backend verification.
Paid order becomes failed
A stale response overwrote a terminal state. Enforce one-way transitions and compare version or updated timestamp inside the transaction.
FAQ
Questions developers ask
Should I use status checks instead of webhooks?
Use signed webhooks for prompt events and status checks for recovery, customer refreshes, and scheduled reconciliation. They solve different failure modes.
Can I check with client_txn_id?
Yes. Use the same stable client_txn_id you stored when creating the order, or use the returned order_id.
How often should status be checked?
Use a bounded schedule with backoff. The exact interval depends on your checkout UX and operational limits; avoid an endless tight loop.