UPI API Integration Guide for Indian Fintech Apps

UPI handles the majority of retail payments in India. If you are building a
fintech app, marketplace or SaaS billing product, UPI will be your
default rail
. This guide walks through the full UPI API surface
— collect, pay, refund, AutoPay — with runnable examples and a production-readiness
checklist.

1. UPI architecture in one diagram (in words)

At the protocol level there are four parties: your app (merchant/PSP client),
the merchant PSP (an RBI-licensed PA-PG or a UPI-enabled bank),
NPCI (which routes the request through the central UPI switch) and the
remitter PSP (the customer’s bank). Your API client only ever talks to
the merchant PSP. Everything below that is NPCI’s concern — but the error codes
that bubble up to you are NPCI’s, so knowing the layering helps with
debugging.

2. Authenticating to the UPI API

Most UPI API vendors use a bearer-token OAuth2 client-credentials flow. You
exchange a client_id + client_secret pair for a
short-lived access token, then send that token on every request.

curl -X POST "https://api.nxtbanking.com/oauth/token" 
  -H "Content-Type: application/json" 
  -d '{"client_id":"CK_xxx","client_secret":"CS_xxx","grant_type":"client_credentials"}'
# => {"access_token":"eyJhbGci...","expires_in":3600,"token_type":"Bearer"}

3. UPI Collect — requesting a payment

A collect request pushes a payment prompt to a VPA (Virtual Payment
Address) such as ravi@okhdfc. The customer approves or declines on
their UPI app. Keep four things in mind:

  • Idempotency — always send a unique merchant_txn_id and reject duplicates on your side.
  • Expiry — NPCI’s default collect expiry is 3 minutes; configure it explicitly.
  • Reference remarks — max 50 chars, no special characters beyond space, dot, hyphen.
  • Minimum amount — 1 INR; maximum 1 lakh per transaction (merchant-category-dependent).
curl -X POST "https://api.nxtbanking.com/upi/v1/collect" 
  -H "Authorization: Bearer $TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "merchant_txn_id": "ORD-2026-00042",
    "vpa":             "ravi@okhdfc",
    "amount":          499.00,
    "currency":        "INR",
    "remarks":         "Order #42 subscription renewal",
    "expiry_minutes":  3,
    "callback_url":    "https://shop.example.com/webhooks/upi"
  }'

A successful response returns status: "INITIATED" and a
bank_rrn once NPCI accepts it (usually within 200–800 ms). The
final status arrives via webhook, not in the HTTP response.

4. UPI Pay — pushing money out (payout-style)

UPI Pay is the mirror of collect — you send money to a VPA. This is
what you use for refunds, creator payouts, gig-worker disbursals, and affiliate
commissions. The main compliance point: your aggregator must be
PPI-licensed or an RBI-authorised PA-PG
to originate push payments; if
you are building on a neo-bank API, they’ll already be licensed.

5. Webhooks — the only source of truth

UPI is asynchronous. Treat the initial HTTP response as “accepted for
processing” only. Your webhook handler must:

  1. Verify the HMAC-SHA256 signature (see our webhook-signature guide).
  2. Be idempotent on merchant_txn_id — the same event can arrive 2–3 times.
  3. Respond with HTTP 200 within 5 seconds; process asynchronously if needed.
  4. Handle the terminal statuses: SUCCESS, FAILED, EXPIRED, DECLINED.
// Node.js — minimal idempotent handler
app.post('/webhooks/upi', express.raw({type:'application/json'}), (req, res) => {
  const sig = req.get('X-NxtB-Signature');
  const expected = crypto.createHmac('sha256', WEBHOOK_SECRET)
                         .update(req.body).digest('hex');
  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).end();
  }
  const evt = JSON.parse(req.body);
  if (await alreadyProcessed(evt.id)) return res.sendStatus(200);
  await processEvent(evt);        // update DB, notify customer, etc.
  await markProcessed(evt.id);
  res.sendStatus(200);
});

6. AutoPay mandates

Recurring subscriptions (OTT, SaaS, insurance premiums) use UPI
AutoPay
— a mandate the customer approves once, after which you can
debit up to a pre-agreed cap on a schedule. Three endpoints:
/mandate/create, /mandate/execute,
/mandate/revoke. Key constraints set by NPCI (January 2026 guidelines):

  • Maximum mandate amount per debit: 15,000 INR (higher limits require additional factor of auth).
  • Pre-debit notification must be sent to the customer ≥24 hours in advance.
  • Mandate state is versioned — always store the mandate_id and version.

7. Common failure modes & their real meanings

NPCI codeWhat it really meansYour action
ZATransaction declined by remitter bankSurface to user; no retry.
ZMInvalid UPI PIN (3rd attempt locks VPA for ~24h)Stop retrying; ask user to re-enter PIN in their UPI app.
U30Debit has been done, but credit is pending at beneficiary bankKeep the txn “processing”; it’ll resolve in T+1.
XHRemitter bank not availableSafe to retry after 30 seconds.
U69Collect expiredCreate a new collect; do not auto-retry the old one.

8. Production checklist

  • ☐ HMAC verification on every webhook
  • ☐ Idempotency store with ≥ 7-day retention
  • ☐ T+1 reconciliation cron against settlement file
  • ☐ Prometheus metrics: collect-p50, collect-p99, webhook-lag, decline-rate by code
  • ☐ Playbook for “U30 stuck” and “mandate-version mismatch”
  • ☐ RBI data-localisation: payment data stored only in India-region infra

Further reading on NxtBanking

Know More