Published on November 2026 • 5 min read
A first-principles walkthrough of UPI — VPAs, PIN trust, debit-before-credit coordination, pending payments, and net settlement.

I paid ₹80 for an auto and the driver’s speaker announced it out loud. My bank, his bank, and something in the middle all agreed in seconds.
I build backends that move data around, and I realised I had no idea how those few seconds actually work.
One disclaimer before we start: NPCI doesn’t publish its internals. What follows is built from public docs and engineering write-ups, so treat it as a simplified model, not a blueprint.
You want to send ₹500 from your HDFC account to a shopkeeper with an SBI account.
HDFC and SBI are two different companies with two different databases. There is no single UPDATE query that touches both. They don't share a transaction, they won't lock accounts for each other, and they definitely don't trust some random app on your phone.
So why can’t your app just call your bank? Because your bank can take the money out, but it has no way to put it into SBI. Someone has to sit in the middle, talk to every bank, and make sure the debit on one side and the credit on the other behave like one thing. In under five seconds. Hundreds of millions of times a day.
That someone is NPCI’s UPI switch.
Nobody wants to type an account number and IFSC code to pay for chai. So UPI adds a layer of indirection: the UPI ID, officially called a VPA (virtual payment address), like bob@axis.
If you’ve worked with DNS, this will feel familiar. bob@axis is a name, not an address. The part after the @ is the handle, and it tells the switch which bank owns that name. NPCI keeps a mapping of handles to providers, sees @axis, and asks Axis Bank "who is bob?" Axis looks up its own database and returns the real account number and IFSC.
Two nice things fall out of this. Your account number never has to be printed on a QR code. And you can often relink the same ID to a new bank account. One more level of indirection fixes the problem, like it always does.
The switch also does this lookup before it touches any money, so it never ends up debiting you for a payee who doesn’t exist.
Here’s the part that surprised me. Your payment app never sees your PIN.
PIN entry happens inside NPCI’s common library, which runs in the app but the app can’t read it. The PIN gets encrypted there, in a form that only your bank can decrypt. In public-key terms: anyone can lock the box, only your bank has the key. The app forwards a locked box, the switch forwards a locked box, and only your bank opens it.
And even your bank doesn’t store your PIN. It stores a salted hash, the same way a sane website stores passwords. The UPI spec says banks can’t keep the PIN even in encrypted form.
There’s a second factor too. When you register, the app records a fingerprint of your device and binds your account to it. So a payment needs something you know (the PIN) and something you have (your phone). Steal someone’s PIN and you still can’t pay from your own phone.
Now the fun part. How do you make two independent banks act like one transaction?
The textbook answer is two-phase commit: ask both banks to lock, then both commit. In the real world, in practice, banks won’t hold a customer’s account locked while it waits on someone else over the network. So UPI doesn’t even try.
Instead, the switch acts as a coordinator, running each payment through a small state machine. Something like:
INITIATED → DEBITED → SUCCESS
The switch tells your bank: verify the PIN, check the balance, debit ₹500. Your bank does that in its own normal database transaction. Only after the switch hears “debited” does it tell SBI: credit ₹500. SBI does that in its own transaction. Then both apps get the green tick.

The order is the entire trick. Debit always comes before credit.
Think about what each failure looks like. If the debit fails, nothing happened. If the debit succeeds and the credit fails, money is stuck somewhere, but it’s recoverable, because there’s a real debit you can reverse. What you can never get is a credit without a debit, which would mean the system just printed money. Failures can strand money. They can’t create it.
Also note what the switch doesn’t do: it never holds the funds. It routes messages and keeps the record of what happened. If you know the saga pattern from microservices, this is basically it. Local transactions, a fixed order, and a compensating action if something breaks.
Networks are slow, and bank servers fall over on Diwali. So what happens when your bank debits you, but SBI’s reply never comes back?
This is the state everyone has seen: money gone, app says pending. The switch doesn’t actually know yet whether the credit landed.
The wrong move is to just send the credit again. If the first one actually went through and only the reply got lost, now the shopkeeper got paid twice.
Instead, UPI has a separate status-check message, ReqChkTxn, which asks a bank "what happened to this transaction?" Asking is safe because it doesn't change anything. Based on the answer, the payment either gets marked successful or the debit gets reversed and you get your money back. For person-to-person payments, the rules put a deadline of about a day on that reversal, and banks that miss it owe the customer a penalty.
What ties all of this together is the transaction ID. Every payment carries a unique ID from the start, and every party uses it as an idempotency key. If a bank sees a debit request with an ID it has already processed, it just returns the old result instead of debiting again. That’s why tapping Pay twice on a laggy network doesn’t charge you twice.
Here’s the twist that gave this post its title. When the shopkeeper’s phone dings, no money has actually gone from HDFC to SBI.
Their banks have updated their own ledgers, so the shopkeeper can spend the money right away. But between the banks, nothing has moved yet. Moving real money for every ₹20 chai would be insane at UPI’s volume.
So NPCI keeps a tally. Several times a day, in settlement cycles, it works out each bank’s net position. For example, if HDFC’s customers sent SBI’s customers ₹900 crore and SBI’s customers sent ₹850 crore back, one ₹50 crore transfer settles both directions. Those net amounts settle through the banks’ accounts at the RBI.
Your payment is instant. The money catches up in batches.
You probably won’t build a national payment switch. But the patterns here show up in normal backend work all the time:
UPI isn’t magic. It’s a coordinator, a careful ordering, and a lot of bookkeeping. Which, honestly, makes it more impressive.