Payment verification

Verify UPI payment status from your backend

Check a UPI order using order_id or client_txn_id, reconcile uncertain results, and update fulfilment only after server-side validation.

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

01

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.

02

Use a state machine

Allow pending to become paid, expired, or failed. Never let a later stale response downgrade a final paid order.

03

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. 1

    Select an unresolved order

    Choose a payment_pending order whose next verification time has arrived and lock it against concurrent workers.

  2. 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. 3

    Validate immutable fields

    Compare tenant, local reference, expected INR amount, and the current state before accepting a status transition.

  4. 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

ts
const 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.

Build the real flow

Move from guide to a verified ₹1 payment

The dashboard checklist takes you through merchant connection, payment verification, webhook testing, and go-live readiness.

Start setup