Design a payment gateway for merchants (Razorpay)
The interviewer asks
“Design a payment gateway like Razorpay that lets Indian merchants accept UPI, cards, netbanking and wallets through one checkout and one API. Focus on routing payments to banks and networks with the best success rate, settling money to merchants, and telling merchants reliably what happened.”
What a strong answer looks like
A strong answer frames the gateway as a multi-tenant layer between thousands of merchants and many banks, networks and NPCI. The merchant creates an order, the hosted checkout collects the method, and the payment service runs a per-payment state machine (created → authorized → captured, or failed) through method-specific adapters: card acquirers via the networks, UPI via a PSP bank and NPCI, netbanking via bank redirects. The India-specific heart is smart routing: the same card or UPI payment can go through several acquiring banks or PSPs, and success rates change minute to minute, so a router chooses the terminal using live success-rate and latency data, with health-based failover. Around this: card tokenisation as required by RBI (no storing of raw card numbers by merchants), a ledger and settlement engine that pays merchants T+1/T+2 from the nodal/escrow account after fees and GST, reliable signed webhooks, and reconciliation with every bank's MIS files. Deep dives: smart routing, late success and reconciliation, settlements, and multi-tenant isolation during festive peaks.
Concepts to mention
1 Requirements
Functional
- Merchant onboarding with API keys; merchants create orders and receive payments via hosted checkout, SDKs or S2S APIs.
- Support UPI (intent, collect, QR), cards (debit/credit, with 3DS/OTP), netbanking, wallets, EMI and pay-later.
- Route each payment to an acquirer/PSP terminal chosen for success rate, cost and health.
- Auto or manual capture, refunds (full and partial), and payment status APIs.
- Signed webhooks for payment, refund and settlement events.
- Settle collected money to merchants (default T+2, instant for a fee) after fees and taxes.
- Dashboards and reports; reconciliation with bank and network files.
- Save cards for repeat customers via network tokens.
Non-functional
- Gateway-added latency under 150 ms p99; total payment time dominated by bank/NPCI and user action.
- 99.99% availability; one failing bank must not affect payments routed elsewhere.
- Success rate is a product metric: routing should lift it by measurable points.
- Peak 20k payments/s during festive sales and big events, with large single merchants.
- Money is never lost: every payment reaches a final state and is reconciled within T+1.
- PCI DSS compliance for card data; RBI tokenisation rules; Indian payment data stored in India.
Out of scope (say it out loud)
- Merchant KYC and risk underwriting details.
- Building the UPI app (covered by the UPI design).
- Lending products like merchant cash advance.
2 Estimates
3 API
| Endpoint | What it does |
|---|---|
POST/v1/orders | Merchant creates an order {amount, currency, receipt}; idempotent on receipt or Idempotency-Key. |
POST/v1/payments/create | Checkout submits the method details {order_id, method, vpa|card_token|bank}; returns next action (redirect, UPI intent, OTP). |
POST/v1/payments/{id}/capture | Capture an authorised payment (manual capture merchants). |
POST/v1/payments/{id}/refund | Refund {amount}; idempotent. |
GET/v1/payments/{id} | Status for merchants that poll after a webhook delay. |
POST/callbacks/{bank} | Bank/PSP/network callbacks with the result; verified by signature or checksum. |
GET/v1/settlements?from=&to= | Settlement batches with linked payments, fees and taxes. |
4 Data model
orders / paymentsPostgres/MySQL sharded by merchant_idorder_idmerchant_idamount_paisestatus; payment_idorder_idmethodterminal_idgateway_refbank_ref (RRN/UTR)statuserror_codeversionOne order may have several payment attempts. Payment state transitions are conditional updates with an outbox.
terminalsPostgres + in-memory configterminal_idacquirer/PSPmethods supportedMDR costlimitsmerchant categoriesstatusA terminal is a merchant ID at an acquiring bank or PSP. Routing chooses among eligible terminals.
routing_statsRedis / in-memory sliding windows (fed by Flink)(method, issuer or bank, terminal) → attemptssuccessesp95 latencyerror codes over last 1530 minFresh signal for routing; Flink aggregates payment outcome events.
token_vaultPCI zone, HSM-encryptednetwork token referencecard fingerprintlast4networkexpiryRBI rules: merchants and gateways do not store full card numbers; network tokens (Visa/Mastercard/RuPay) are stored instead.
ledgerPostgres, append-only double-entryjournal_idaccount (merchant balance, fees, GST payable, nodal account, refunds)debitcreditpayment_idSource for settlement amounts; must reconcile with the nodal/escrow bank statement daily.
settlementsPostgressettlement_idmerchant_idperiodgrossfeestaxrefundsnetutrstatusCreated by batch; UTR from bank on payout completion.
webhook_deliveriesPostgres / Kafkaevent_idmerchant_idurlattemptsnext_attempt_atlast_statusAt-least-once delivery with exponential backoff for up to 24 h.
5 Architecture
Hover a box to highlight its connections.
6 Request flows
Card payment with smart routing
- 1Merchant server creates an order for ₹2,499; checkout opens and the customer picks a saved card (network token).
- 2Payment service creates a payment attempt and asks the router for a terminal.
- 3Router filters terminals eligible for this merchant, card network and card type (e.g. a RuPay debit card from Bank X), then scores them by last-5-minute success rate for this issuer, latency and MDR cost; it picks Acquirer B because Acquirer A's success rate for Bank X dropped from 92% to 70%.
- 4Adapter sends the auth request through the acquirer; the issuer requires OTP, so the customer is redirected to the bank's 3DS/OTP page.
- 5Callback from the acquirer arrives with success; payment moves to authorized and, for auto-capture merchants, to captured, with an outbox event.
- 6Merchant gets payment.captured webhook; checkout returns the signed payment ID to the merchant page, which the merchant server verifies with its secret.
UPI intent payment
- 1Customer chooses UPI; the router picks a PSP bank based on live UPI success rates.
- 2Gateway asks the PSP to create a collect or intent transaction and returns an intent link; the customer's UPI app opens with the amount and merchant VPA.
- 3Customer enters UPI PIN in their app; NPCI routes the debit to their bank and credit to the gateway's merchant account at the PSP.
- 4PSP sends a callback with status and RRN; if no callback arrives within the expected window, a status poller checks with the PSP within NPCI's allowed limits.
- 5Payment becomes captured; webhooks and settlement follow.
Settlement to merchant (T+2)
- 1Acquirers and PSPs credit the nodal/escrow account with net amounts; recon matches their MIS files to payments.
- 2Settlement job computes per merchant: captured amount - refunds - fees - GST on fees, from the ledger.
- 3It creates payouts with idempotent references and calls the bank's payout API (NEFT/RTGS/IMPS); bank returns a UTR.
- 4Settlement records the UTR and emits settlement.processed webhooks.
7 Deep dives
Smart routing to maximise success rate
In India, the same payment can often go through several acquiring banks or PSPs, and success rates vary by issuer, card type, method and time of day; a bank's server can degrade for 20 minutes during a sale. A few percentage points of success rate is real revenue for merchants, so routing is a core feature. The router runs in-process on the payment service with config and stats in memory, so a decision takes under 5 ms. Step one: eligibility, from rules (merchant category, method, card network, amount limits, merchant's own acquirer contracts). Step two: scoring, using live success rates per (method, issuer bank, terminal) over sliding windows of 1, 5 and 30 minutes computed by Flink from payment outcome events and pushed to Redis. Blend success rate, latency and cost. Step three: exploration, sending a small share of traffic (a few percent) to non-preferred terminals so the system notices when a degraded terminal recovers, like a multi-armed bandit. Health checks open a circuit on a terminal with error spikes. Be careful to count only failures caused by the bank or network, not user drop-offs or wrong OTPs, otherwise the router punishes healthy terminals. Retry on another terminal is possible only for some failures and only before the customer is charged; never retry when the result is unknown.
Late success, unknown status and reconciliation
Bank and NPCI systems often reply late or not at all. A UPI payment can show failed or pending on our side while the customer's account was debited; a card authorisation can time out after approval. Handle three cases. First, pending/unknown: do not mark failed; poll the bank or PSP status API with backoff and within their rate limits (NPCI limits how often status checks can be made), and keep the checkout showing 'processing' for a while. Second, late success after the order was cancelled or the customer paid again: the payment becomes captured; for merchants with auto-refund settings, a job refunds late successes that were not used, otherwise the merchant is told via webhook. Third, end-of-day truth: every bank and network sends MIS/settlement files. Recon matches each line to a payment by gateway_ref or RRN/ARN and amount, and builds exception queues: debited but failed in our system, success but missing in file, amount mismatch. Most exceptions resolve automatically by moving the payment to the correct state and posting ledger corrections; customers who were debited for a failed payment get auto-refunds within the RBI turnaround time (TAT) framework, which also mandates compensation for delays.
Settlement engine and the ledger
Gateways in India must keep merchant funds in a nodal or escrow account and settle according to RBI's payment aggregator guidelines. The ledger is the source of truth for what each merchant is owed. Every captured payment posts: debit receivable from acquirer, credit merchant balance (gross minus fee), credit fee revenue, credit GST payable. Refunds reverse the merchant part. When an acquirer credits the escrow account, recon moves the money from receivable to escrow cash. Settlement runs per cycle: for each merchant, sum settleable balance (payments captured before the cut-off and already received from acquirers), subtract holds for disputes or risk reserves, and create a payout. Payouts are idempotent by (merchant, cycle) so a re-run never pays twice. Instant settlement is a product on top: pay from the gateway's own working capital before acquirers settle, for a fee, which is credit risk and needs limits. Daily, the escrow bank statement must equal the sum of ledger escrow entries; any difference is a high-severity alert.
Multi-tenancy and festive peaks
A few merchants (a ticketing site during a cricket ticket drop, an e-commerce sale at midnight) can send 50x normal traffic. Protect everyone else. Rate-limit and quota per merchant at the edge with burst allowances agreed in advance; isolate the biggest merchants into dedicated shards or cell pools so a surge does not exhaust shared database connections; use per-bank bulkheads so a slow bank's adapter cannot consume all threads. Pre-scale before known events and run load tests with banks, since bank capacity, not ours, is often the limit; the router can spread load across acquirers to avoid tripping a single bank's limits. Keep checkout static assets on a CDN. Shed non-critical work first under pressure: dashboards, reports and analytics consumers can lag; payment creation and callbacks cannot.
8 Trade-offs
Route by live success rate vs fixed priority
Fixed priority lists are easy to reason about and match contract cost, but react slowly to bank outages. Live scoring lifts success rate but needs reliable stats, careful failure classification and exploration traffic. Most gateways combine rules for eligibility and cost with live scoring.
Auto-capture vs manual capture
Auto-capture reduces unclaimed authorisations and is the default for most merchants. Manual capture lets merchants confirm stock first, but uncaptured payments must be auto-refunded after a window, which customers dislike.
Instant settlement vs T+2
Instant settlement improves merchant cash flow but the gateway pays before receiving funds, taking credit and fraud risk. Offer it with limits based on merchant history and refund rates.
Webhooks vs polling for merchants
Webhooks are timely but can be delayed or lost on the merchant side. Provide both: at-least-once signed webhooks with retries and a status API, and tell merchants to verify signatures and handle duplicates.
9 Bottlenecks
A single bank's capacity
During a sale, one issuer or acquirer hits its TPS limit and starts timing out. The router spreads traffic, circuit-breaks the degraded terminal and uses exploration to detect recovery.
Hot merchant shard
One giant merchant overwhelms a shard. Move large merchants to dedicated cells, and partition their payments by payment_id within the cell.
Recon at month-end and after big sales
File sizes jump 10x. Run recon in Spark over S3 files partitioned by bank and date, and match with hash joins rather than per-row DB lookups.
10 Failure handling
Bank callback never arrives
The payment stays pending; status pollers query the bank with backoff. End-of-day MIS files settle the final state. Customers debited for failed payments get auto-refunds within TAT.
Webhook endpoint of a merchant is down
Deliveries retry with exponential backoff for up to 24 hours; after that the merchant is alerted and can fetch events via API. Other merchants are unaffected because each merchant has its own delivery queue.
Router stats pipeline (Flink) stops
Stats go stale; the router detects stale timestamps and falls back to static priority rules with health checks, so payments continue at a slightly lower success rate.
11 What impresses
- Explains that success rate is the product, and designs routing with live stats, exploration and failure classification.
- Handles UPI and card late successes with pollers, recon and auto-refunds within RBI TAT.
- Knows merchants cannot store raw card numbers in India and uses network tokens.
- Describes settlement from an escrow account with fees, GST, reserves and idempotent payouts.
- Isolates huge merchants into cells and uses per-bank bulkheads.
- Says never to retry on another terminal when the first outcome is unknown.
12 Mistakes
- Designing a single-processor flow and ignoring routing across banks.
- Marking a payment failed on timeout, leading to double debits.
- Retrying an unknown card authorisation on a second acquirer.
- Settling merchants from payment status without a ledger and reconciliation.
- Storing raw card numbers outside a PCI vault.
- Letting one merchant's spike take down shared infrastructure.
13 Follow-ups
Lessons this design uses
Practice questions
- Design the public API of a payment gateway like Razorpay or Stripe: how a merchant creates an order, collects payment, refunds, and learns the result.
- You key payment events by merchant_id. One large merchant produces 40% of all traffic, so one partition is always lagging while others are idle. What do you do?
- Your payments app is expanding to the Middle East and Europe. Indian payment data must stay in India under RBI rules, and EU user data has GDPR requirements. How do you partition data across regions?
- Model the lifecycle of an online payment in your system. What states does it go through and how do you keep transitions correct?
- Product wants 'save card for faster checkout' on your shopping app. What are the rules in India, and how would you build it?
- You run a payment aggregator. Merchants are paid out T+1 for the payments they collected. How does money flow, and how would you build the settlement system?
- Your app uses three payment gateways. One of them has a bad hour with card success rates dropping from 75% to 40% for HDFC cards. How would you route payments to maximise success?
- A customer tells their bank they never received a ₹12,000 phone and raises a chargeback two months after the purchase. How should your platform's systems handle disputes?
- You integrate with two payment providers. One of them starts failing 40% of card payments during a festive sale. How would you use circuit breakers and routing to protect conversions?
- You are designing checkout for an Indian e-commerce app that wants to save customers' cards for one-click payments. How do you handle card data and encryption?
Saved on this device. Create a free account to keep it on every device.
Practise this with Sam
A real mock interview, out loud, with an honest scorecard. Free to start.