KnowSys

Designing UPI

Anjali scans the QR code taped to a chai stall and pays ₹20 from her phone, and two seconds later the stall's speaker says the money has arrived. We'll design the system that moves it between two banks that share nothing: the switch in the middle, addresses and QR strings, debit-then-credit, the PIN, what happens when a bank goes silent halfway, reconciliation, festival-day bursts and UPI Lite.

⏱ 50 min read◆ IntermediateAssumes: the Stripe case study (chapter 52), chapter 31 (distributed transactions) helps, chapter 40 (reliability) helps
Start reading

It's a quarter past eight in the morning outside Andheri station in Mumbai. Anjali stops at Ramesh's chai stall on her way to the office and asks for a cutting chai and a bun-maska, ₹20 in all. Taped to the side of the counter is a square of laminated card with a QR code on it. She opens a payments app on her phone, points the camera at the code, types 20, enters her four-digit PIN, and taps Pay. Before she's picked up the glass, a small speaker beside the kettle announces in a flat robotic voice that twenty rupees have been received.

A small roadside sweet shop with a blue tin front, a shopkeeper at the counter, and several purple PhonePe QR code cards hanging around the shop
A sweet shop in North 24 Parganas, West Bengal, in 2025. Look along the top beam and the pillars: the purple cards are PhonePe QR codes, hung wherever a customer might stand. A card like these is all a small shop needs to accept UPI.Photo: Yooktashree barai, CC BY-SA 4.0, via Wikimedia Commons

From where Anjali stands, that was one tap. Underneath, it's more interesting. Anjali's money is in an account at State Bank of India. Ramesh's is at Bank of Baroda. Those two banks run separate computer systems in separate buildings, with separate databases, and neither can write to the other's. Her app belongs to a third company, and the QR code on the counter was printed by a fourth. Yet ₹20 has to leave one bank and arrive at the other within a couple of seconds, exactly once, and if anything goes wrong in between, somebody has to notice and put it right. On its busiest days now, the system does this more than 800 million times.

The system is India's Unified Payments Interface (UPI), run by the National Payments Corporation of India (NPCI), a not-for-profit company owned by banks and set up under the oversight of the Reserve Bank of India (RBI), the country's central bank. In this case study we'll design it the way an engineer would: start from the obvious design, find exactly where it breaks, and fix it. The question we'll keep coming back to is this: when Anjali taps Pay, how does ₹20 move from her bank to Ramesh's, in two seconds and exactly once, when the two banks share no database and either of them might go quiet halfway through? We'll go from the shape of the network down to the fields of a QR string, the life of one transaction through a timeout, the reconciliation that closes it, and the tricks for surviving the first of the month.

The Stripe case study (chapter 52) already covered card payments, idempotency keys and double-entry ledgers, and chapter 31 covered two-phase commit and sagas. We'll lean on both and point back to them; this chapter is about what's different when the thing in the middle is a national switch between hundreds of banks.

01What we're building, and how big

1.1What it has to do

Moving Anjali's ₹20 comes down to a short list:

  1. Pay anyone by a name, without knowing their bank or account number: a phone number, a short address like ramesh.tea@okaxis, or a QR code.
  2. Move money between any two banks in the network, whichever app each person uses.
  3. Confirm in seconds to both sides, so Ramesh can hand over the chai.
  4. Ask the payer's permission in a way no app, shop or thief can fake.
  5. Never lose or duplicate money: if the payment fails anywhere, Anjali gets her ₹20 back, on a known deadline.
  6. Settle up between banks so that, at the end of the day, SBI has paid Bank of Baroda what its customers owe.

And the qualities it needs while doing that:

  • Fast: a couple of seconds end to end, including two banks' systems.
  • Open: any bank or app that meets the rules can join, and every one can reach every other.
  • Correct where money is concerned: every rupee that leaves one account lands in another or comes back.
  • Available at the worst moments: the first of the month, festival days, evening rush, and while some bank somewhere is having a bad day.

This list has something Stripe's didn't. Stripe was one company processing payments for its own customers; it controlled its own databases. UPI is a set of rules and a switch sitting between hundreds of independent banks, each with its own systems, and the switch can't reach into any of them. Most of this case study is about what you can guarantee when the money lives in systems you don't control.

1.2How big is it?

NPCI publishes UPI's numbers every month. In September 2026, UPI carried 24.07 billion transactions worth ₹29.37 lakh crore (about ₹29 trillion), with more than 750 banks live on the network. August 2026 is the record month so far, at 24.51 billion transactions. Across the financial year April 2025 to March 2026 it carried about 241.6 billion transactions worth about ₹314 lakh crore, according to a government release from August 2026. RBI's annual report for 2024-25 put UPI's share of all retail payments in India, by count, at 84%.

It didn't start that way. UPI went live as a pilot with 21 banks in April 2016 and was rolled out to the public that August, when it handled about 90,000 transactions in the month. By December 2019 the monthly count was 1.31 billion; by December 2022, 7.83 billion; by December 2024, 16.73 billion.

MonthBanks liveTransactions in the monthValue
Aug 201621about 90,000₹3 crore
Dec 20191431.31 billion₹2.03 lakh crore
Dec 20223827.83 billion₹12.82 lakh crore
Dec 202464116.73 billion₹23.25 lakh crore
Sep 2026750+24.07 billion₹29.37 lakh crore

(A lakh is 100,000 and a crore is 10 million, so ₹1 lakh crore is ₹1 trillion.)

The daily numbers matter more for the design than the monthly ones. In September 2026 UPI averaged about 802 million transactions a day, the first month above 800 million, and the busiest days run higher than that. An ordinary day in mid-2026 carries roughly 750 to 800 million.

A hand holding a printed city bus ticket from Hyderabad showing a total of 30 rupees and Payment Mode: UPI
A city bus ticket from Hyderabad, June 2025: ₹30, “Payment Mode: UPI”. Most UPI payments look like this one and Anjali's, a few tens of rupees. So the count is enormous while the average value is small.Photo: TG09Z, CC BY-SA 4.0, via Wikimedia Commons
Your turn: design it before reading on

On an ordinary day in September 2026, UPI carried about 800 million transactions. What's the average rate per second across that day? Payments aren't spread evenly: NPCI's own circulars name 10:00 to 13:00 and 17:00 to 21:30 as the hours with the highest transactions per second. What might the rate be in those hours?

02Version 1: every app talks to every bank

2.1The obvious design

Here's the design you might reach for first. Anjali's app needs to take ₹20 from her SBI account and give it to Ramesh's Bank of Baroda account. So the app's company signs an agreement with SBI, gets an API, and asks SBI to debit Anjali. Then it signs an agreement with Bank of Baroda and asks it to credit Ramesh. Do the same for every other bank, and the app can pay anyone.

Version 1: each app integrates with each bank
Anjali's appAnother appA third appSBIAnjali's accountBank of BarodaRamesh's accountHDFC Bank
Step 1. Anjali's app asks SBI, through a private API, to debit her ₹20.
1 / 3

Three things break. First, the count. With a apps and b banks, there are a × b integrations to build, test and keep working, and every new bank has to integrate with every app before its customers can be paid from them. Second, nobody owns the payment as a whole. If SBI debits Anjali and then Bank of Baroda's API doesn't answer, the only party that knows the payment is half-done is the app, and the app is a private company with no authority over either bank. Third, there's the money between the banks. SBI has taken ₹20 from Anjali and Bank of Baroda has given ₹20 to Ramesh; SBI now owes Bank of Baroda ₹20, and somebody has to keep track of millions of such debts and get them paid.

2.2Put a switch in the middle

All three problems have the same fix: put one system in the middle that every bank and every app connects to once. A system that receives a payment message from one party and routes it to another is called a switch, and UPI's switch is run by NPCI. Each bank and each app now builds one integration, to the switch, so the count is a + b instead of a × b. The switch sees every message of every payment, so it owns the state of each payment from start to finish. And because it sees every debit and credit between every pair of banks, it can add them up and tell each bank what it owes the others.

There's one more piece. The members that connect to the switch are banks (and a few other licensed payment institutions), so an app like PhonePe or Google Pay doesn't connect to NPCI on its own; it connects through a bank that sponsors it. That sponsoring bank is called a payment service provider (PSP), and the app built on top of it is a third-party application provider. PhonePe's @ybl addresses, for example, belong to its PSP relationship with Yes Bank, and Google Pay's @okaxis addresses to its relationship with Axis Bank.

Put together, a UPI payment involves up to four parties around the switch, which NPCI's procedural guidelines describe as "two PSPs … and two banks acting as Remitter & Beneficiary Bank":

PartyIn Anjali's paymentIts job
Payer PSPAnjali's app and the bank behind itCaptures her intent and her PIN, sends the request to the switch
Remitter bankSBIHolds Anjali's account; checks the PIN and debits her
NPCI's UPI switchNPCIRoutes every message, tracks the transaction, computes settlement
Payee PSPThe bank behind @okaxisKnows who ramesh.tea@okaxis is and which account to credit
Beneficiary bankBank of BarodaHolds Ramesh's account; credits him

"Remitter" is the bank that sends money and "beneficiary" is the bank that receives it. Notice that four of the five roles can be four different organisations, and the PSP banks needn't be the banks where Anjali and Ramesh hold their money. That's what makes UPI open: Anjali can use any app with her SBI account, and Ramesh can receive into Bank of Baroda through any app that issued him an address.

A paper notice inside a Bengaluru city bus with a QR code and the words Scan using any BHIM UPI enabled Apps, with Axis Bank and BHIM UPI logos
A QR code inside a Bengaluru city bus in 2020: “Scan using any BHIM UPI enabled Apps”. The code was issued through Axis Bank, but a passenger can pay from any app and any bank, because every one of them connects to the same switch.Photo: Mallikarjunasj, CC0, via Wikimedia Commons
Decision

How should apps and banks reach each other?

Point to point
Each app integrates with each bank directly.
  • No central operator to trust
  • No single system whose failure stops everything
  • apps × banks integrations
  • Nobody owns the whole payment
  • Interbank debts tracked by nobody
chosen
A central switch
Every bank and app connects once, to a switch run by a neutral operator.
  • apps + banks integrations
  • One place that owns each payment's state
  • One place that computes what banks owe each other
  • The switch must never go down
  • The switch's operator sets everyone's rules

India chose a switch, as almost every country has for card payments, ATM networks and interbank transfers. NPCI already ran the switch for India's ATM network and for IMPS, an older instant transfer service, so UPI was built as a new layer over the same idea, by an operator owned by the banks and overseen by RBI. The cost of the choice is that the switch becomes the one system that can stop every payment in the country. Much of what follows comes from that.

So now there's a hub, and Anjali's app knows to send her payment to it. But the app still has to say who the money is for, and Anjali doesn't know Ramesh's bank or account number. That's the next problem.

03Paying a name: addresses and the QR code

3.1A name instead of an account number

A bank account in India is identified by an account number and an IFSC, an 11-character code naming the bank branch. Asking Anjali to type sixteen digits and a branch code to pay ₹20 would end the idea at once, and printing them on a card at the stall would hand them to anyone who walked past.

UPI's answer is an address that looks like an email address: ramesh.tea@okaxis. It's called a virtual payment address (VPA), or in the apps, a UPI ID. The part after the @ is the handle, and it names the payee PSP that issued the address. Before the @ comes a name that PSP chose with Ramesh. Only that PSP knows which real account ramesh.tea points to; NPCI's guidelines describe the address being resolved by the "respective PSP", using its own mapping table.

So to find out where Anjali's ₹20 should go, the switch reads the handle, okaxis, looks up which PSP owns it, and asks that PSP: who is ramesh.tea? The PSP answers with the account details and Ramesh's registered name. Nobody but that PSP and the switch ever sees his account number. Anjali's app shows her "Ramesh Tea Stall" before she pays. That's her chance to notice if she's about to pay the wrong person.

A standing sign reading BHIM / UPI Accepted Here with a large QR code, the Virtual ID shauryasmarak@allbank and Pay To SHAURYA SMARAK, from Indian Bank
A static QR at a memorial in Bhopal, 2021, with its address printed underneath: shauryasmarak@allbank. The handle allbank names the PSP, here Allahabad Bank (now part of Indian Bank), and “Pay To SHAURYA SMARAK” is the registered name a payer's app shows before the PIN.Photo: Suyash.dwivedi, CC BY-SA 4.0, via Wikimedia Commons

?Why does the handle name the PSP, not Ramesh's bank?

Because the PSP is the party that knows the mapping, and the switch needs to know whom to ask. Ramesh's bank is Bank of Baroda, but his address was issued by the PSP behind Google Pay, and if he switches his receiving account to another bank tomorrow, his address and his QR code stay the same; only the PSP's mapping changes. It's the same layering as DNS: a name points to whoever is authoritative for it, and the authority can change the answer without anyone reprinting the name. Phone numbers work too: NPCI runs a central mapper that links a mobile number to a default account, for people who type a number instead of an address.

?Why not one global directory, like Brazil's?

Brazil's instant payment system, Pix (we'll meet it properly later), keeps every key (phone number, email, tax ID or random key) in one directory run by the central bank, called DICT, which held over 920 million keys according to the central bank's 2026 report. That gives one authoritative answer and makes keys portable between banks. UPI spreads the directory across PSPs instead, with each handle owner answering for its own names. The cost is an extra hop to the payee PSP on every payment; the benefit is that the switch holds no customer directory of its own, and each PSP can mint addresses without asking anyone.

3.2What's inside the QR code

zoomUPIPayee addressQR codeupi://pay URI

Ramesh's QR code doesn't contain an image of anything or a link to a website. Decoded, it's a short line of text, a URI, defined in NPCI's UPI linking specification. A URI with the scheme upi and the host pay is a request to pay, and its parameters are the payment's details:

C++
upi://pay?pa=ramesh.tea@okaxis&pn=Ramesh%20Tea%20Stall&cu=INR

The same format is used when one app opens another to pay, for example a shopping site handing off to your payments app; on a phone that's called an intent, and the specification calls the URI a deep link. Version 1.6 of the specification, dated November 2017, lists these parameters:

FieldMeaningNotes from the specification
paPayee addressThe VPA. Required.
pnPayee nameShown to the payer
mcMerchant category codeFour digits saying what kind of business it is
tidTransaction IDGenerated by the PSP when the app creates the request
trTransaction referenceThe merchant's own order or bill number; "mandatory for merchant transactions"
tnNoteFree text, shown to both sides
amAmount"If 'am' is not present then field is editable" by the payer
mamMinimum amountThe least the payer may enter
cuCurrency"ONLY 'INR'"
urlReference URLA link to the order or bill details
modeHow the request was started01 QR, 02 signed QR, 04 intent, 06 NFC, and others
orgidWho generated it000000 when the merchant generated it
mid, msid, mtidMerchant, store and terminal IDsFor larger merchants
signSignatureBase64-encoded digital signature over the other fields

A code printed once and taped to the counter, like Ramesh's, is a static QR: it carries the address and name, and Anjali types the amount. A till at a supermarket instead shows a dynamic QR for each bill, which also carries the amount and a reference number. Because am is present, Anjali's app shows the amount and doesn't let her change it, and the reference tr lets the supermarket match the incoming payment to the right bill.

This short program parses both kinds of string the way an app's scanner would. It uses Python's urlsplit to separate the scheme, host and query, and parse_qs to split the query into fields and undo the %20 escapes (a space can't appear raw in a URI, so it's written as %20). Then it checks the two things an app must check before going further: the scheme is upi://pay, and the address has a handle after an @.

Parse a static and a dynamic UPI QR string
python
Python
from urllib.parse import urlsplit, parse_qs, unquote
 
# What the phone's camera reads from two QR codes at the stall
static_qr  = "upi://pay?pa=ramesh.tea@okaxis&pn=Ramesh%20Tea%20Stall&cu=INR"
dynamic_qr = ("upi://pay?pa=ramesh.tea@okaxis&pn=Ramesh%20Tea%20Stall"
              "&mc=5814&tr=ORD20261011A7&am=20.00&cu=INR&tn=2%20cutting%20chai")
 
FIELDS = {"pa": "payee address (VPA)", "pn": "payee name", "mc": "merchant category code",
          "tr": "transaction reference", "am": "amount", "cu": "currency", "tn": "note"}
 
def parse(uri):
    parts = urlsplit(uri)
    if parts.scheme != "upi" or parts.netloc != "pay":
        raise ValueError("not a UPI payment intent")
    q = {k: v[0] for k, v in parse_qs(parts.query).items()}
    user, _, handle = q["pa"].partition("@")
    if not user or not handle:
        raise ValueError("pa must look like name@handle")
    return q, handle
 
for name, uri in [("static", static_qr), ("dynamic", dynamic_qr)]:
    q, handle = parse(uri)
    print(f"{name} QR, {len(uri)} characters")
    for k, v in q.items():
        print(f"  {k:3} {FIELDS.get(k, '?'):26} {v}")
    print(f"  -> ask the PSP behind @{handle} who '{q['pa']}' is")
    if "am" in q:
        print(f"  -> amount fixed at Rs {q['am']}; the payer can't edit it")
    else:
        print("  -> no amount: the payer types it in")
    print()
output
C++
static QR, 61 characters
  pa  payee address (VPA)        ramesh.tea@okaxis
  pn  payee name                 Ramesh Tea Stall
  cu  currency                   INR
  -> ask the PSP behind @okaxis who 'ramesh.tea@okaxis' is
  -> no amount: the payer types it in
 
dynamic QR, 117 characters
  pa  payee address (VPA)        ramesh.tea@okaxis
  pn  payee name                 Ramesh Tea Stall
  mc  merchant category code     5814
  tr  transaction reference      ORD20261011A7
  am  amount                     20.00
  cu  currency                   INR
  tn  note                       2 cutting chai
  -> ask the PSP behind @okaxis who 'ramesh.tea@okaxis' is
  -> amount fixed at Rs 20.00; the payer can't edit it

Look at what's in the static string: 61 characters and three fields, and nothing secret. That's deliberate. A QR code at a stall can be photographed by anyone, so it carries only what's needed to receive money, the same as writing your address on an envelope. Its dynamic cousin adds the merchant category (5814 is the international code for fast-food restaurants), the order reference and a fixed amount. Notice also the first thing the parser hands on: the handle. Everything the switch does next starts from @okaxis.

A version 4 QR code with coloured overlays marking the position, alignment and timing patterns, format and version information, and the data and error-correction area
The anatomy of a QR code. The three big squares let the camera find and orient the code; the coloured strips tell it the size and error-correction level; everything else is the data, here the bytes of a URI like Ramesh's, plus error-correction codes that let a scratched or stained card still scan.Image: Sarang, public domain, via Wikimedia Commons

3.3Can a QR code be forged?

Since a static QR code is a printed card, the obvious attack is to paste your own code over Ramesh's. Customers would then pay a stranger, and the payment would go through perfectly, because nothing in the string is wrong; it's someone else's address. UPI's defences here are on the people, not the protocol: the app shows the payee's registered name ("Ramesh Tea Stall") before Anjali enters her PIN, and the speaker on Ramesh's counter announces every payment he receives, so a customer whose payment didn't make it speak is noticed at once.

For larger merchants the specification offers more: a signed QR, where the sign field holds a digital signature computed with the merchant's private key over the other fields, using RSA with SHA-256. The payer's app checks the signature with the merchant's public key, which PSPs download from NPCI daily, and refuses a string that's been edited. That stops someone changing the amount or the address on a dynamic code. It can't stop someone replacing a whole static card with their own valid one, so the name check still matters.

So the switch now knows whom Anjali wants to pay. Next, the money has to move, and the order in which things happen turns out to be most of the design.

04One payment, leg by leg

4.1The messages behind one tap

NPCI's procedural guidelines describe the push payment flow in five steps, with named messages. Request messages start with Req and responses with Resp, so ReqPay is "please make this payment" and RespPay the answer. Here is Anjali's payment, hop by hop:

Anjali pays ₹20 to ramesh.tea@okaxis
ReqPaywho is ramesh.tea?debitcreditAnjali's apppayer PSPPayer PSP bankthe app's sponsorNPCI UPI switchroutes, recordsPayee PSP@okaxisSBIremitter bankBank of Barodabeneficiary bankRamesh's speaker
Step 1. Anjali scans the code, types 20 and enters her PIN. The app sends the payment, with the PIN encrypted, through its sponsoring bank to the switch as a ReqPay.
1 / 5

The switch does no money-moving of its own. It holds no accounts for Anjali or Ramesh; it's a router with a memory. Each bank does a local transaction in its own database: SBI subtracts ₹20 from a row, Bank of Baroda adds ₹20 to a row. What the switch adds is the record that these two local changes belong to the same payment, under one transaction ID, and the order in which they're asked for.

4.2Why debit first?

Predict before you read on

The switch could ask Bank of Baroda to credit Ramesh first and SBI to debit Anjali afterwards, or the other way round. Which order is safer, and why?

This is the same reasoning as a saga in chapter 31: run the steps one at a time, each a local transaction, and if a later step fails, undo the earlier ones with a compensating step. In UPI the compensating step for a failed credit has a name, a debit reversal: the switch tells SBI to put the ₹20 back. NPCI even publishes, per bank, how many reversals were needed and what fraction succeeded, which we'll look at in section 8.

4.3Pay and collect

Everything so far is a pay request, also called a push: the payer starts it and pushes money out. UPI also had the opposite, a collect request, or pull: the payee starts it by sending the payer a request for an amount, the payer's app shows "Ramesh is requesting ₹20", and if the payer approves with their PIN, the same debit-then-credit flow runs. Collect is handy for online shops (type your UPI ID at checkout, approve the request in your app) and for splitting a bill with friends. NPCI's guidelines gave collect requests a default expiry of 30 minutes.

The trouble is the screen the payer sees. A collect request asks you to enter your PIN to send money, and fraudsters learned to send requests with notes like "enter PIN to receive your refund". A person used to entering their PIN to make things happen would enter it, and pay. Because the request comes from the payee, the payer is the only check. In July 2025, NPCI's circular OC-220 set the end of it for payments between people: "by 1st October 2025 UPI P2P Collect shall not be allowed to be processed in UPI." Collect requests from merchants continue, under the merchant's PSP's controls.

All of this assumes that the ReqPay came from Anjali. Anyone who can make the switch believe a request came from her can empty her account. That's the next section.

05Who's allowed to say "debit"

5.1Binding the app to a SIM

SBI is about to take ₹20 from Anjali because a message said she wanted it to. Two questions have to be answered before it does: did this message come from Anjali's phone, and did Anjali herself approve this payment? UPI answers them with two factors, something she has and something she knows.

Something she has is her phone, or more precisely, the SIM card with her registered mobile number. When Anjali first sets up the app, the app sends an SMS from her phone to the PSP. NPCI's guidelines call it "an automated outward encrypted SMS (Mobile number to PSP system) which hard binds the Mobile number with the device." Because the SMS travels from her phone through the mobile network, the PSP learns from the network itself that this device holds the SIM for her number. That's probably much harder to fake than a number typed into a form. This is called device binding. From then on, requests from that app installation on that phone carry identifiers tied to the binding, and a request from any other device doesn't.

The bank then finds Anjali's accounts by that mobile number (it's the one registered with SBI), and she sets up her PIN. To prove she's the account holder, she enters the last six digits of her debit card and its expiry date, plus a one-time password (OTP) that SBI sends to her registered number. Since 2021 she can instead use an OTP from Aadhaar, India's national identity system, if her Aadhaar number is linked to the account.

5.2A PIN the app never sees

Something Anjali knows is her UPI PIN, four or six digits. That PIN belongs to her bank, SBI. And here's the problem: she types it into an app written by a different company, running on her phone. If that app could read the PIN, then every PSP in the country would be holding the keys to accounts at every bank, and one leaked database or one dishonest employee would be enough.

UPI's answer is that the PIN screen doesn't belong to the app. NPCI ships a piece of software called the common library (CL), which every UPI app must embed. When it's time to enter the PIN, the app hands control to the CL, which draws the keypad and captures the digits itself. The CL encrypts the PIN together with the transaction's details into a credential block, using RSA with a 2048-bit NPCI public key that the library holds. Anjali's app receives only the encrypted block, and passes it along with the payment.

Where Anjali's PIN can be read
encrypted blockre-encrypted for SBICommon libraryNPCI code in the appAnjali's appsees ciphertext onlyPayer PSP banksees ciphertext onlyNPCI switchdecrypts, re-encryptsSBI's HSMdecrypts and checks
Step 1. Anjali types her PIN on a keypad drawn by NPCI's common library, not by the app. The library encrypts the PIN with NPCI's public key into a credential block.
1 / 4

A hardware security module (HSM) is a tamper-resistant box that holds encryption keys and does operations with them without ever letting the keys out; the procedural guidelines say the issuer bank "has to mandatorily decrypt … using HSM only". So the PIN exists in readable form only on Anjali's keypad and inside security hardware, never in the app's memory or a PSP's logs.

The library also has to know it's talking to a genuine app. On first use it registers itself with NPCI's servers: the app asks for a challenge, fetches a token through a ListKeys request, and registers with a keyed hash (an HMAC) over the device ID, the app ID and the mobile number. Tokens are refreshed periodically; an NPCI circular in 2021 extended its validity from 30 to 90 days.

?Why not let each bank ship its own PIN screen?

Because then every app would need every bank's code inside it: the a × b problem from section 2 again, this time on the phone. One library, one format and one public key at the switch turn it back into a + b: apps embed one library, and banks each give the switch one key.

Decision

How should the payer's approval travel from the phone to their bank?

The app sends the PIN
The app collects the PIN and passes it, protected by TLS, to the bank.
  • Simple
  • Each app controls its own interface
  • Every app and PSP can read every PIN
  • One breach exposes customers of every bank
chosen
NPCI library, end-to-end encryption
A library from the switch operator captures the PIN and encrypts it to a key the app doesn't hold.
  • Apps never see PINs
  • One standard library for all apps and banks
  • Every app must embed and update NPCI's code
  • The switch is in the trust path

UPI's openness depends on this choice. Letting any company build a payments app is only safe if a payments app can't learn your PIN. The cost is that NPCI's code runs inside every UPI app, and NPCI's systems briefly handle the PIN in their own secure hardware when re-encrypting it for the bank.

5.3Small payments without a PIN

Typing a PIN for a ₹20 chai is a bit of friction that slows a queue. In October 2025, an NPCI circular added on-device biometric authentication, a fingerprint or face check by the phone, "in lieu of UPI PIN" for payments up to ₹5,000, along with face authentication through Aadhaar for setting or resetting the PIN. In July 2026 the biometric limit was raised to ₹10,000, from 7 August 2026. Section 9 covers a second way small payments avoid the PIN, UPI Lite, which also takes load off the banks.

So now SBI is sure the request is Anjali's, debits her ₹20, and says so. Next the switch asks Bank of Baroda to credit Ramesh. What happens if Bank of Baroda never answers?

06Two banks, no shared database

6.1Why there's no commit across both banks

Before we deal with Bank of Baroda going silent, it's worth seeing why the problem can't be designed away. If the debit at SBI and the credit at Bank of Baroda were rows in one database, we'd wrap them in one transaction and they'd happen together or not at all. They're in two databases owned by two companies. The textbook tool for making two databases commit together is two-phase commit, from chapter 31: a coordinator asks both to prepare, each locks what it needs and promises it can commit, and then the coordinator tells both to commit.

Applied to UPI, the switch would be the coordinator, and that's where it falls apart. While SBI waits to hear "commit", Anjali's ₹20 is locked in a prepared state; if the switch is slow or the message is lost, SBI can't decide on its own, because the whole point of having prepared is that it promised to wait. Now multiply by 750 banks, thousands of payments a second and any bank's systems pausing at any moment: every bank's ledger would be holding locks on behalf of every other bank's problems. And a bank's core banking system, the decades-old system holding its accounts, is not something any switch operator gets to install a new protocol into.

So UPI does what chapter 31 recommends when you can't hold locks across organisations: each step is a local transaction committed immediately, the steps run in a fixed order, and a failed later step is undone by a compensating step. The switch's job is to remember, for every payment, which steps have happened, so that it always knows what still has to be done or undone.

6.2Ramesh is paid now; the banks settle later

There's a second thing that doesn't move in those two seconds: the bank's money. When Bank of Baroda credits Ramesh ₹20, it hasn't received ₹20 from SBI. It has received a message from the switch saying SBI has debited Anjali. Bank of Baroda pays Ramesh out of its own funds, trusting that SBI will pay it back.

That repayment is called settlement. Banks in India hold settlement accounts at RBI, and the switch adds up, for each bank, everything its customers sent and received through UPI during a window of time. Over a window, SBI's customers pay Bank of Baroda's customers some amount and Bank of Baroda's customers pay SBI's some other amount, and only the difference needs to move. Netting all banks against each other this way is called deferred net settlement: deferred because it happens after the customers' payments, and net because only each bank's overall position moves. Each bank ends a window owing or owed one number, and those numbers are posted to the banks' accounts in RBI's real-time gross settlement system, RTGS.

The stone front of the Reserve Bank of India building in Mumbai behind a red railing
The Reserve Bank of India in Mumbai. Every bank on UPI keeps a settlement account here, and these accounts are where SBI finally pays Bank of Baroda, as part of one net sum per cycle.Photo: DesiBoy101, CC BY 4.0, via Wikimedia Commons

NPCI runs these windows, called settlement cycles, many times a day. From 1 August 2024, its circular OC-197 moved UPI to ten settlement cycles a day, and members have to keep enough funds in their RTGS settlement accounts every day of the year. A September 2025 circular kept ten cycles for ordinary payments, from 3 November 2025, and split dispute adjustments into two separate cycles of their own.

The customers' payments are instant; the banks' payments are batched
every legnet positionsAnjaliSBI customerSBIdebits AnjaliNPCI switchrecords every legBank of Barodacredits RameshSettlementnet per bank, 10 cycles a dayRBI RTGSbanks' settlement accounts
Step 1. In two seconds, SBI debits Anjali and Bank of Baroda credits Ramesh, each in its own database. No money has moved between the two banks yet.
1 / 4

?What if SBI couldn't pay at the end of the cycle?

Then Bank of Baroda would have paid Ramesh with money it never receives. That's settlement risk, and every deferred net system carries it. NPCI's rule that banks must keep funds in their settlement accounts every day of the year is one guard against it. What happens when a member does default is a matter for NPCI's settlement rules, which we won't go into here. The design point is that banks trust each other for a few hours at a time so their customers don't have to wait.

Decision

How should money move between the banks?

Gross, in real time
Every payment moves money between the two banks' central bank accounts as it happens.
  • No settlement risk: the payee's bank is paid before it credits
  • Nothing to reconcile at the end of the day
  • Every payment needs the central bank's system in its path
  • Each bank must keep enough funds at every moment for every payment
chosen
Deferred net, in cycles
Banks credit customers at once and settle the net difference several times a day.
  • The central bank's system handles a few postings per bank per cycle, not billions
  • Banks need far less money parked in settlement accounts
  • Banks carry each other's credit risk for hours
  • Every cycle has to be reconciled

UPI settles net, in cycles. Brazil's Pix made the other choice: the central bank's own instant payment system, SPI, settles each Pix payment individually and immediately between the two institutions' accounts at the central bank, around the clock. The US FedNow service, launched in July 2023, also settles each payment individually in the banks' accounts at the Federal Reserve. Both remove settlement risk at the price of putting the central bank's system in the path of every payment. India put a switch in the path instead, and kept RBI's system for a few large postings a day.

So each payment touches the switch and two bank databases, and the banks square up later. Now we can face the case we've been putting off.

07When the credit leg goes silent

7.1Three answers, and no answer

SBI has debited Anjali ₹20. The switch has sent Bank of Baroda the credit request. Bank of Baroda can come back with one of three things, or nothing:

  • Success. Ramesh is credited. The switch tells both sides and the payment is done.
  • A clear refusal. Ramesh's account is frozen, say. Nothing was credited. The switch sends SBI a debit reversal, SBI gives Anjali back her ₹20, and her app says the payment failed. Annoying, but nothing is unknown.
  • Silence. The request timed out. Perhaps Bank of Baroda never got it; perhaps it got it, credited Ramesh, and the reply was lost; perhaps it's still working on it. From the outside, the switch can't tell which.

The third case is the one Stripe's Maya faced in her tunnel (chapter 52), but with a difference that makes it harder. Stripe could make retries safe with an idempotency key, because Stripe controlled both the key store and the charge. Here, the switch can ask Bank of Baroda again, but it can't look inside Bank of Baroda's database, and it can't move the money itself. Whatever it decides, two independent ledgers have to end up agreeing.

?Why not just treat silence as failure and refund Anjali?

Because in some of those silent cases Bank of Baroda did credit Ramesh. Refund Anjali as well, and ₹20 has been created out of nothing: Anjali has her money back and Ramesh has his. Treat silence as success instead, and in the cases where the credit never happened, Anjali has lost ₹20 that went nowhere. Either guess is wrong some of the time, and with hundreds of millions of payments a day, "some of the time" is thousands of people.

Here's a simulation of 100,000 payments of ₹20. One percent are clearly refused by the payee bank. Half a percent time out, and of those, 60% were in fact credited before the reply was lost (the exact share is made up; what matters is that it's neither 0% nor 100%). The program applies three policies to the timeouts: refund at once, assume success, or mark the payment as unknown and settle it later against the payee bank's own records. It then adds up the money: everything debited must have been either credited or refunded, so the gap, debited minus credited minus refunded, should be zero.

Three ways to handle a credit leg that times out
python
Python
import random
random.seed(7)
 
N = 100_000          # payments of Rs 20, each debited from the payer first
P_DECLINE = 0.01     # payee bank answers "no" (account frozen, say)
P_TIMEOUT = 0.005    # payee bank goes silent: did the credit happen or not?
P_SILENT_OK = 0.6    # of those silent ones, how many were in fact credited
 
def run(policy):
    payer_out = payee_in = refunded = timeouts = 0
    for _ in range(N):
        payer_out += 20                       # debit leg succeeded
        r = random.random()
        if r < P_DECLINE:
            refunded += 20                    # clear "no": reverse at once
        elif r < P_DECLINE + P_TIMEOUT:
            timeouts += 1
            credited = random.random() < P_SILENT_OK
            payee_in += 20 if credited else 0
            if policy == "timeout = failed":
                refunded += 20                # reverse blindly
            elif policy == "timeout = done":
                pass                          # assume it went through
            else:  # "deemed, then reconcile"
                if not credited:              # the bank's records say no credit
                    refunded += 20
        else:
            payee_in += 20                    # normal success
    gap = payer_out - payee_in - refunded     # money that left and arrived nowhere
    return payer_out, payee_in, refunded, gap, timeouts
 
print(f"{'policy':24}{'debited':>11}{'credited':>11}{'refunded':>10}{'gap':>8}")
for policy in ["timeout = failed", "timeout = done", "deemed, then reconcile"]:
    random.seed(7)
    out, inn, ref, gap, t = run(policy)
    print(f"{policy:24}{out:>11,}{inn:>11,}{ref:>10,}{gap:>8,}")
print(f"\n{t} of {N:,} payments timed out on the credit leg")
output
C++
policy                      debited   credited  refunded     gap
timeout = failed          2,000,000  1,975,400    30,880  -6,280
timeout = done            2,000,000  1,975,400    20,400   4,200
deemed, then reconcile    2,000,000  1,975,400    24,600       0
 
524 of 100,000 payments timed out on the credit leg

Read the gap column. With "timeout = failed", it's −₹6,280: the system refunded 314 payments that had in fact reached the payee, so ₹6,280 was paid out twice. With "timeout = done", it's +₹4,200: 210 people lost ₹20 each to payments that never arrived. Only the third policy balances, and it can only do so because it waits for an answer that comes from the payee bank's own books instead of guessing. Notice too how small the problem is in count, 524 payments out of 100,000, and how much machinery it's going to need.

7.2Pending, deemed, and checking the status

UPI's rules changed their mind on exactly this point. NPCI's original procedural guidelines from 2016 treated a timeout as a decline and promised that "there will not be any transactions with pending status." That's the first policy in the simulation, and it pays some money out twice. Circulars in early 2017 introduced deemed approval, the third policy.

A deemed-approved payment is one where, in NPCI's words, "credit confirmations are not received online from the beneficiary banks". The debit has happened; the credit's outcome is unknown; and the responsibility for finding out moves to the beneficiary bank, which must check its own records and either confirm the credit or return the money. NPCI publishes each beneficiary bank's deemed-approved percentage every month; in August 2026, Yes Bank, the largest receiving bank, had 0.01% of its 10 billion incoming transactions deemed.

Meanwhile Anjali is standing at the stall looking at a spinner, and then a screen that says the payment is pending. Her app can ask the switch what happened with a check transaction status request (ChkTxn), and the switch asks the bank. Done carefully, this resolves most unknown payments within a minute or two: Bank of Baroda's systems catch up, find the credit or don't, and the switch marks the payment as a success or reverses the debit.

Anjali's ₹20 through a credit timeout
InitiatedReqPay receivedDebitedSBI took ₹20Credit unknowndeemed / pendingSuccessRamesh has ₹20ReversedAnjali has ₹20 back₹20 · txn 7731
Step 1. The switch receives Anjali's ReqPay and gives it a transaction ID. Nothing has moved yet.
1 / 5

Notice that "Credit unknown" is a real state the system records, with rules for leaving it, and not a gap in the design. A payment can sit there for minutes, or, if a bank's systems are badly broken, until the end of the day.

7.3Deadlines, compensation, and the end-of-day files

What if a check-status doesn't settle it? The backstop is a deadline set by the regulator. In September 2019, RBI's circular on harmonising turnaround times for failed transactions set, for UPI transfers between people: "If unable to credit the beneficiary account, auto reversal (R) by the Beneficiary bank latest on T + 1 day. ₹100/- per day if delay is beyond T + 1 day." Here T is the calendar day of the payment, so a failed payment from Monday must be reversed by the end of Tuesday. For payments to merchants the limit is T + 5 days. And the compensation is to be paid "suo moto", on the bank's own initiative, "without waiting for a complaint". That turns a stuck payment from the customer's problem into the bank's cost. It's a design choice too: a bank that leaves payments stuck pays for it every day.

The tool that makes "by T + 1" possible is reconciliation: comparing two independent records of the same events and resolving every difference. Every settlement cycle, the switch produces files listing every transaction and how it ended according to the switch. Every bank compares those files line by line against its own ledger. A payment the switch shows as deemed but Bank of Baroda's ledger shows as credited is confirmed; one the ledger doesn't show is returned, and the reversal flows back to SBI and to Anjali. NPCI's back office for this is called URCS, and its dispute system, UDIR (Unified Dispute and Issue Resolution), lets banks and apps raise and track individual cases.

Closing the loop on an unknown payment
check statusChkTxnfilesfilesAnjali's appshows pendingNPCI switchtxn 7731: deemedBank of Barodaown ledgerBack officesettlement files, URCSUDIRdisputesSBIreverses if needed
Step 1. Anjali's app asks the switch for the status of transaction 7731. The switch asks Bank of Baroda, at most a few times and spaced out, as section 8 explains.
1 / 5

08When a bank is the weak link

8.1Business declines and technical declines

Every payment in section 7 depended on two banks' systems answering promptly, and the switch can't make them. Some banks run modern systems; others run core banking systems designed long before anyone imagined 800 million payments a day. So a large part of UPI's operation is measuring the banks and making the measurements public.

NPCI splits failed payments into two kinds. A business decline is a refusal for a reason about the customer: in NPCI's glossary, "a customer entering an invalid pin, incorrect beneficiary account etc." A technical decline is a refusal because something broke: "unavailability of systems and network issues on bank or NPCI side." Business declines are the system working correctly. Technical declines are the ones a bank can fix.

Every month NPCI publishes a table of the top 50 remitter banks and the top 50 beneficiary banks with those rates. Here is part of the remitter table for August 2026:

Remitter bankTransactionsApprovedBusiness declinesTechnical declinesDebit reversal success
State Bank of India6,846 million90.78%9.11%0.10%96.60%
HDFC Bank1,786 million93.07%6.93%0.00%100.00%

The beneficiary table has the same columns, plus the deemed-approved percentage from section 7. NPCI also publishes a monthly list of bank downtimes, with each incident's length.

?Why publish each bank's failure rate?

Because the switch has no other lever over a bank's systems, and the tables give it one. An app can see which banks are failing its users and route its own users' attention accordingly; a bank's management can see where it stands against its peers; and the regulator can see who needs pushing. It's a bit like a status page inside a company: a number that everyone can see gets fixed faster.

8.2When checking makes things worse

Section 7 introduced check-status as the polite way to learn what happened to an unknown payment. In April 2025 it turned out to be the problem. On 12 April 2025, NPCI said it was facing "intermittent technical issues, leading to partial UPI transaction declines," and news reports at the time described hours of failures. Two weeks later, on 26 April, NPCI's circular OC-215 named the cause it was guarding against: a "high number of 'Check Transaction Status' APIs by PSP banks at a very high Transactions Per Second (TPS) rate in repetitive manner".

You can see how that happens with a little arithmetic. When a bank slows down, more payments become unknown, so apps send more status checks, which land on the same struggling systems and slow them further. That loop is a retry storm, the same feedback chapter 40 describes for retries in general. This program estimates how much extra traffic status checks add when one bank holding a fifth of payers' accounts loses 30% of its replies during a 15,000-a-second evening peak (all three numbers are illustrative), under three checking policies.

How much traffic do status checks add when one bank is slow?
python
Python
# One slow bank at 7 pm: how much extra traffic do status checks add?
PAYMENTS_PER_SEC = 15_000      # an illustrative evening peak
SLOW_BANK_SHARE  = 0.20        # this bank holds 20% of payers' accounts
UNKNOWN_RATE     = 0.30        # while it's struggling, 30% of its replies go missing
 
unknown_per_sec = PAYMENTS_PER_SEC * SLOW_BANK_SHARE * UNKNOWN_RATE
 
policies = {
    "app polls every 5 s for 2 min": 120 // 5,
    "app polls every 15 s for 2 min": 120 // 15,
    "at most 3 checks, first at 90 s": 3,
}
 
print(f"payments in doubt: {unknown_per_sec:,.0f} per second\n")
print(f"{'policy':34}{'checks/s':>10}{'vs payments':>13}")
for name, checks_each in policies.items():
    checks = unknown_per_sec * checks_each
    print(f"{name:34}{checks:>10,.0f}{checks / PAYMENTS_PER_SEC:>12.0%}")
output
C++
payments in doubt: 900 per second
 
policy                              checks/s  vs payments
app polls every 5 s for 2 min         21,600        144%
app polls every 15 s for 2 min         7,200         48%
at most 3 checks, first at 90 s        2,700         18%

With eager polling, status checks outnumber the payments themselves, 21,600 a second against 15,000, and every one of them goes to the bank that's already in trouble. Capping each unknown payment at three checks cuts that roughly eightfold. Waiting 90 seconds before the first check helps in a way the program doesn't show: it gives the bank time to recover before anyone asks.

That's what OC-215 imposed. The first check should come "after 90 seconds" (45 to 60 seconds once new timers came in), with a "maximum of 3 check transaction status APIs, preferably within 2 hours". After that, apps should wait for the settlement files or make one check through UDIR. No check at all is allowed after errors listed in the circular, such as a connection timeout or "no route to host", which already mean the other side can't be reached; the payment is treated as failed.

8.3Shorter timeouts and rationed API calls

NPCI followed with two more changes in 2025. Circular OC-214, issued the same day as OC-215, said that from 16 June 2025 the time allowed for a pay request and its response was cut from 30 seconds to 15, and for check-status and reversal from 30 seconds to 10. A shorter timeout sounds harsher, but it means a stuck payment is declared unknown and sent down the recovery path sooner, instead of holding Anjali at a spinner and holding threads at every bank along the way.

The second change rationed the calls that don't move money at all. Circular OC-215A, from May 2025, limited balance enquiries to 50 per app per customer a day, and only when the customer asks, with banks required to return the balance with every successful payment instead. It limited listing a customer's accounts to 25 a day per app, allowed address validation only when the customer is about to pay, and pushed the execution of recurring mandates, such as subscriptions, out of peak hours, which it defined as "10:00 hrs to 13:00 hrs and from 17:00 hrs to 21:30 hrs."

These rules protect the network from its own clients on an ordinary bad day. The predictable bad days, when everyone in the country pays at once, need something more.

09Festivals, the first of the month, and UPI Lite

9.1When the bursts come

UPI's daily statistics show two kinds of burst. The first is the turn of the month. The first days of a month, when salaries land and rent, bills and subscriptions go out, run well above an ordinary day, and value spikes even harder than count: an ordinary day in September 2026 carried about ₹0.98 lakh crore.

The second is festivals. In October 2025, the days before Diwali (20 October) ran high, with 754 million payments on 18 October, a record at the time. Festival shopping, gifts and travel push the days before up; the holiday itself is quieter.

A street in T. Nagar, Chennai, packed from side to side with shoppers under shop signs
Festival-season shopping in T. Nagar, Chennai. Every one of these people may pay several shops in an afternoon, and so may millions of others in every city at once. Unlike a viral moment, these crowds come on dates everyone knows in advance.Photo: Arunsarv, CC BY-SA 4.0, via Wikimedia Commons

Both kinds are predictable, and that shapes the defences. Capacity can be added ahead of a known date, as the JioHotstar case study (chapter 69) does before a final. Background work, such as recurring mandates, can be moved away from peaks, as OC-215A did. And, most interesting for the design, the smallest payments can be taken off the busiest path altogether.

?What does NPCI's switch run on?

Very little of it is published. NPCI announced two Tier IV data centres in 2020, in Chennai and Hyderabad. Its peak transactions per second, how payments are spread across sites, and how a site failure is handled are unpublished. What the design probably needs is clear enough from this chapter: the switch must keep each transaction's state durably (because section 7 depends on it), must keep running if a whole site is lost, and must have spare capacity well beyond the first-of-the-month peak, because the banks behind it can't absorb a sudden backlog either.

9.2UPI Lite: small payments off the core banking system

Look at Anjali's ₹20 from SBI's side. To approve it, SBI's core banking system had to verify the PIN, lock her account row, check the balance, write a debit, and later write the reversal if needed, all within a few seconds, for a sum a bit bigger than a bus fare. Most UPI payments are small, and every one of them is a write to the busiest database a bank owns.

UPI Lite, launched in September 2022, takes those payments off that path. A customer moves a small amount from their bank account into a Lite balance, a top-up that goes through the normal UPI flow with the PIN. Payments from the Lite balance then need no PIN, and, in NPCI's description, they work by "reducing load on core banking systems in real-time"; the remaining balance is shown in the app by NPCI's common library. Since a February 2025 circular, the limits are ₹1,000 per payment and ₹5,000 in the Lite balance. UPI Lite X, a variant, goes further: small payments between two phones over NFC with no network at all, for either side.

A ₹20 payment from UPI Lite
no PINdebit Litecredittop-upAnjali's appLite balance ₹480NPCI switchSBI Lite ledgersmall, fastSBI core bankingtouched at top-upBank of Barodacredits Ramesh
Step 1. Earlier in the week, Anjali topped up ₹500 into UPI Lite, with her PIN. That was one ordinary debit from her account in SBI's core banking system.
1 / 4

How each bank stores and posts Lite balances internally isn't published; the diagram shows the idea, a small separate ledger in front of the core system. It's a clear trade: a capped balance and no PIN, so a lost phone can lose at most ₹5,000, in exchange for taking the most numerous payments off the most loaded system. It's the same move as a cache in front of a database (chapter 25) or a prepaid transit card: absorb many small operations in a cheap place and settle with the expensive one rarely.

Decision

How do you stop tiny payments from overloading the banks?

Scale every bank's core system
Require banks to handle the full peak of every payment in their core systems.
  • One path for every payment
  • No separate balance to explain to customers
  • Hundreds of banks, many on old systems, must all scale together
  • Every ₹10 payment costs a full core-system write
chosen
A capped side balance (UPI Lite)
Move a small amount out once; small payments debit it without the core system or PIN.
  • Far fewer core-system writes
  • Faster and PIN-free at the counter
  • Customers must top up
  • Money at risk on a lost phone, up to the cap

NPCI did both, in a sense: the API limits and response-time rules of section 8 push banks to keep up, and UPI Lite gives them a way to keep the smallest payments out of the queue. Lite's limits have been raised as confidence grew, to ₹1,000 per payment and ₹5,000 in balance in 2025.

9.3Phones without apps, and credit

Two more extensions reach people and money the original design didn't. UPI 123PAY, launched in March 2022, lets feature phones, the keypad phones without app stores that many Indians still use, pay over UPI by calling an interactive voice response (IVR) number, giving a missed call, using an app built into the phone, or through sound-based payments.

A black Nokia 105 keypad phone showing its home screen
A keypad phone of the kind UPI 123PAY was built for: no app store, no camera to scan a QR, but a keypad that can call an IVR number and type a PIN.Photo: Multicherry, CC BY-SA 4.0, via Wikimedia Commons

Credit reached UPI too. Since 2022, RuPay credit cards can be linked to UPI addresses, and since 2023 banks can offer pre-approved credit lines over UPI. In all three, the switch and its flows are unchanged; what changes is how the payer's request is captured, or what kind of account sits behind the debit.

9.4Too much of the network in two apps

One kind of failure the switch can't route around is the failure of an app most people use. In August 2026, by NPCI's app-wise statistics, PhonePe carried about 45.6% of UPI transactions, Google Pay about 32.3% and Paytm about 8.0%. In November 2020 NPCI announced a cap of 30% of UPI volume for any single third-party app, measured over a rolling three months, with time to comply. NPCI has extended the deadline more than once; the latest extension, at the end of December 2024, moved it to 31 December 2026. Whatever happens to the cap, the system design concern behind it is concentration: if one app's outage can stop nearly half the country's payments, the network's redundancy at the switch matters less than it looks.

10The same problem in other countries

10.1Pix, FedNow and the card networks

Other countries have built the same thing with different answers to this chapter's decisions, and comparing them shows which answers were forced and which were choices.

A street fruit stall in Brazil under umbrellas with a hand-written sign reading Morango 3 por 12,00 R$, Aceito Pix
A strawberry seller in Viçosa, Brazil, in 2022: three boxes for R$12, “aceito Pix”. The same moment as Ramesh's stall, on a system with a central directory and gross settlement at the central bank.Photo: Mateus S. Figueiredo, CC BY-SA 4.0, via Wikimedia Commons
UPI (India)Pix (Brazil)FedNow (US)Card networks
Launched201616 Nov 202020 Jul 20231950s onward
Run byNPCI, owned by banksBanco Central do BrasilFederal ReserveVisa, Mastercard and others
AddressesVPAs, resolved by each PSPKeys in one central directory (DICT)Account details; directories left to banksCard numbers
Who starts itPayer (push)Payer (push)Payer (push)Merchant pulls from the card
Bank-to-bank settlementNet, in 10 cycles a dayGross, each payment, in central bank moneyGross, each payment, in Fed accountsNet, usually next day
Scale24.07 billion in Sep 20267.8 billion in Dec 2025about 5 million in Q2 2026

Pix, the closest relative, made a record of 313 million payments on 5 December 2025 and 7.8 billion in that month, according to the central bank's 2026 report on it; its DICT directory held over 920 million keys. FedNow went live with 35 early-adopting banks and credit unions; in the second quarter of 2026 it carried just under 5 million payments, about 55,000 a day. That suggests the hard part of an instant payment system is probably getting banks and customers to use it, more than building the switch. ACI Worldwide's 2024 report on real-time payments put India at 49% of the world's real-time payments by count in 2023, and Brazil at 14%.

The card networks are the oldest relatives. A card payment is a pull: the shop's bank asks the card network to take money from the cardholder's bank, and the network settles between the banks later, net. UPI's pay flow is a push, started by the payer and approved with a PIN on the payer's own device, so there's no card number for a shop to store or leak. Chapter 52 follows a card payment end to end. One more difference is the fee: UPI payments have carried no merchant discount rate, the fee a shop pays per payment, since January 2020. That changes on 15 October 2026: an NPCI circular of 15 September 2026 introduced a fee of up to 0.4%, capped at ₹300, on payments to merchants above ₹2,000, with lower flat fees for some sectors such as fuel and railways. Payments up to ₹2,000, which NPCI says are more than 95% of merchant payments, stay free, and so do small merchants who receive up to ₹1 lakh a month straight into their own accounts. Ramesh's ₹20 costs him nothing.

11The whole system

11.1Every box, and why it's there

UPI, end to end
NPCIReqPayresolvedebitcreditnet positionsAnjali's appwith NPCI's libraryPayer PSP bankUPI switchroutes, transaction statePayee PSP@okaxis directorySBIcore banking + LiteBank of BarodaBack officefiles, URCS, UDIRRBI RTGSnet settlement
Step 1. Anjali scans upi://pay?pa=ramesh.tea@okaxis…, types 20 and enters her PIN in NPCI's library, which encrypts it. Her app's PSP sends ReqPay to the switch.
1 / 6
ComponentWhat it doesAdded because
UPI switchRoutes every message, records each payment's stateapps × banks integrations, nobody owning the payment (§2)
VPAs and PSP directoriesTurn name@handle into an accountAccount numbers are unusable and unsafe to share (§3)
QR / upi://pay URICarries the payee's address, and sometimes amount and referencePaying a shop must take one scan (§3)
Debit-then-credit with reversalMoves money as two local transactionsNo transaction can span two banks (§4, §6)
Device binding and common libraryProves the phone and the PIN without the app seeing itAny company may build an app (§5)
Deferred net settlementBanks square up in ten cycles a dayCustomers can't wait for interbank transfers (§6)
Deemed state, check status, T + 1Gives unknown payments a state, a deadline and an ownerTimeouts leave the credit unknown (§7)
Reconciliation and UDIRCompare independent records; resolve disputesOnly the payee bank's own ledger knows the truth (§7)
Decline statistics and API rulesMeasure banks; ration retries and pollingBanks are the weak link; retries make it worse (§8)
UPI LiteSmall payments from a capped side balanceTiny payments overload core banking systems (§9)

11.2From top to bottom

LevelThe choiceData structure or algorithm
NetworkOne switch between all banks and appsHub routing: a + b connections instead of a × b
AddressingFederated directory by handlename@handle; handle → PSP table at the switch; name → account map at each PSP
Payment requestA URI with named fieldsupi://pay?pa=…&pn=…&am=…&tr=…&sign=…, optionally RSA-signed
One paymentOrdered local transactionsDebit, then credit, then a compensating reversal on failure (a saga)
AuthorisationEncrypt at the keypad, decrypt in hardwareRSA-2048 credential block; re-encryption at the switch; bank HSM
Unknown outcomesA named in-between stateState machine: initiated → debited → deemed → success or reversed
Bank settlementNet, in cyclesPer-bank sums over a window, posted to RTGS
RecoveryCompare recordsLine-by-line reconciliation of settlement files against bank ledgers
LoadBound the retriesAt most 3 status checks, first after 45–90 s; per-customer API quotas

12What goes wrong, and what it cost

12.1Failures this design has to survive

What happensWhat Anjali or Ramesh seesWhat the design does
Wrong PIN or low balance"Payment failed" at onceDebit refused first, so nothing moved (business decline)
Payee bank refuses the credit"Payment failed", money back in secondsDebit reversal to SBI
Payee bank times out"Pending"Deemed state; limited status checks; reversal by T + 1 or ₹100 a day
A bank's systems are downPayments from that bank failTechnical decline, counted against that bank in NPCI's public tables
Apps hammer a slow bank with status checksFailures spread to everyoneCaps on status checks, timers, and API quotas since 2025
A fake QR pasted over the real oneMoney goes to a strangerThe app shows the payee's registered name; speakers announce receipts
A fraudster sends a collect requestA request to "enter PIN to receive"Collect between people switched off from October 2025
First of the monthSlower payments, if anythingCapacity ahead of known peaks, mandates moved off-peak, UPI Lite

12.2The tradeoffs, in one table

DecisionChosenGiven upWhy it was worth it
TopologyA central switchFreedom from one critical systema + b integrations; one owner per payment
DirectoryFederated by PSP handleOne authoritative directoryNo customer directory at the switch; PSPs mint addresses freely
OrderingDebit, then creditMoney briefly out of the payer's account on a failed creditNever pay out money that wasn't collected
AtomicityLocal steps plus reversalAn atomic commit across banksNo cross-bank locks; banks keep their own systems
PINNPCI library, end-to-end encryptedApp freedom over the PIN screenOpen app market without exposing PINs
SettlementDeferred net, ten cycles a dayZero settlement riskRBI's system isn't in every payment's path
TimeoutsDeemed, then reconcileAn immediate answer for every paymentNo money created or lost (§7's TryIt)
Small paymentsUPI Lite with capsPIN on every paymentFar fewer core-banking writes

13Summary

  1. A national payment network needs a switch: with hundreds of banks and apps, point-to-point integration is a × b, and nobody would own the payment or the debts between banks.
  2. A VPA is a federated name: the handle names the PSP that knows the account, so the switch asks it, and Ramesh's QR never shows an account number.
  3. A UPI QR code is a URI with named fields; a static one says only who to pay, a dynamic one fixes the amount and a reference, and a signed one can't be edited.
  4. A payment is two local transactions in order, debit then credit, with a debit reversal when the credit fails, because no transaction can span two banks.
  5. The app never sees the PIN: NPCI's common library encrypts it at the keypad, and only the bank's HSM decrypts it, while device binding ties the app to the SIM.
  6. Customers are paid in seconds, banks later: deferred net settlement in ten cycles a day at RBI, where Pix and FedNow settle each payment gross.
  7. A timeout leaves the credit unknown, and both guesses are wrong; UPI records it as deemed, checks the payee bank, and reconciles against its ledger.
  8. Unknown payments have a deadline and an owner: reversal by T + 1 for transfers between people, or ₹100 a day to the customer.
  9. Banks are the weak link, and retries make it worse: NPCI publishes per-bank decline rates and, since April 2025, caps status checks and API calls.
  10. Bursts are predictable, so capacity is added ahead of the 1st of the month and festivals, and UPI Lite takes the smallest payments off core banking systems.

14Build this

A toy UPI switch.

  • Write three small services: two "banks", each a SQLite database of accounts with debit, credit, reverse and status endpoints, and a "switch" that keeps a table of transactions with a state column.
  • Make the switch run debit then credit, store each state change before acting on it, and reverse the debit when the credit is refused.
  • Make the payee bank occasionally sleep past the switch's timeout, sometimes after committing the credit and sometimes before. Mark those payments deemed.
  • Add a status checker that asks at most three times with growing gaps, and an end-of-day job that compares the switch's table with each bank's ledger and reverses every deemed payment the payee bank can't find.
  • Run 10,000 payments and check the invariant from section 7: total debited equals total credited plus total reversed. Then break the rules (refund on timeout; poll every 100 ms) and watch the invariant or the load go wrong.

15Interview questions

beginnerWhat happens, step by step, when you scan a UPI QR code and pay?›

The app reads a upi://pay URI from the code, which holds the payee's address and perhaps an amount. You enter your PIN on a keypad drawn by NPCI's library, which encrypts it. Your app's PSP sends the request to NPCI's switch. The switch asks the PSP named by the address's handle which account it belongs to, asks your bank to verify the PIN and debit you, then asks the payee's bank to credit the payee, and confirms to both sides. Banks settle the money between them later, in net, several times a day.

beginnerWhy does UPI debit the payer before crediting the payee?›

Because most failures happen at the debit, wrong PIN, low balance, a blocked account, so doing it first means most failed payments fail before any money moves. And if the credit fails after a successful debit, the fix is to give the payer their money back, which is safe; the other order could leave the payee's bank having paid out money nobody collected.

intermediateThe payee bank times out after the payer was debited. What should the switch do?›

Neither refund nor confirm blindly: refunding pays twice when the credit did happen, and confirming loses money when it didn't. Record the payment in a distinct unknown state (UPI's deemed approval), tell the payer it's pending, ask the payee bank for the status a few times with spaced-out checks, and if that doesn't resolve it, settle it against the payee bank's own ledger through the settlement files. Put a deadline and an owner on it: in UPI, the beneficiary bank must reverse an uncredited transfer by T + 1, or pay compensation daily.

intermediateHow does UPI let third-party apps take payments without them seeing your PIN?›

The PIN is captured by NPCI's common library, embedded in every UPI app, which encrypts it with NPCI's public key into a credential block the app can't open. The switch re-encrypts it for the issuing bank, which decrypts it only inside a hardware security module. Separately, device binding by an SMS sent from the phone ties the app installation to the registered mobile number, so a request has to come from that phone and carry the PIN.

deepWhy doesn't UPI use two-phase commit between banks, and what does it use instead?›

Two-phase commit would have each bank lock the funds in a prepared state while it waits for the switch, so a slow switch or a lost message would hold locks in every bank's core system, across organisations that don't share infrastructure or trust. Instead each leg is a local transaction committed at once, in a fixed order, with a compensating reversal when a later leg fails: a saga. The switch records every leg; the unknown outcomes are closed by status checks and, finally, by reconciling settlement files with each bank's ledger. The banks' money moves later still, by deferred net settlement.

deepHow would you keep a slow bank from taking down a national payment network?›

Measure and publish each bank's technical decline rate so there's pressure to fix it. Keep timeouts short so payments to a slow bank fail fast and enter recovery instead of holding resources. Bound the recovery traffic: cap status checks per payment and delay the first one, forbid checks after overload errors, and ration non-payment calls such as balance enquiries, as NPCI did after its April 2025 incidents. Move background work like recurring mandates off peak hours, and take the smallest payments off core banking systems with a side balance like UPI Lite.

16Go deeper

check yourself
A QR code says upi://pay?pa=shop@okicici&pn=Shop&cu=INR. Which party does the switch ask about the address, and can the payer change the amount?›

The PSP that owns the handle okicici, which maps "shop" to an account. There's no am field, so the payer types the amount.

The credit leg fails with a clear refusal. Is the payment deemed?›

No. A clear refusal means nothing was credited, so the switch reverses the debit at once. Deemed is only for the case where the payee bank didn't answer and the credit's outcome is unknown.

A payment between two people on Monday couldn't be credited. By when must the money be back, and what if it isn't?›

By the end of Tuesday (T + 1). After that the bank owes the customer ₹100 for every day of delay, paid without waiting for a complaint.

NPCI UPI product and ecosystem statistics

Monthly and daily volumes and values, app-wise shares, and the top-50 remitter and beneficiary bank tables with business and technical decline rates.

UPI Procedural Guidelines and the UPI Linking Specification (NPCI)

The four-party model, device binding, PIN encryption, and every field of the upi://pay URI.

NPCI circulars OC-197, OC-215, OC-215A and OC-220

Ten settlement cycles a day; limits on status checks and API calls after the April 2025 incidents; the end of collect requests between people.

RBI circular on turnaround times for failed transactions (20 Sep 2019)

T + 1 reversal and ₹100-a-day compensation for UPI and other payment systems.

Banco Central do Brasil, Pix management report (2026)

The other national instant payment system: central directory, gross settlement in central bank money, and its growth since 2020.

FedNow Service quarterly statistics (Federal Reserve)

The US instant payment service's volumes and participants since July 2023.

Designing Stripe

Card payments, idempotency keys and double-entry ledgers: the single-company version of moving money exactly once. Chapter 52.

Distributed Transactions

Two-phase commit, and the sagas and compensations UPI uses instead. Chapter 31.

Reliability

Timeouts, retries, retry storms and load shedding. Chapter 40.

Queueing & Capacity

Why a busy system's latency explodes near saturation, and how to plan for known peaks. Chapter 42.

Designing JioHotstar

Another Indian system built around predictable national bursts. Chapter 69.