Design a real-time transaction processing system for Google Pay.
- Gigs Logic

- Jul 27, 2025
- 4 min read
Updated: Aug 13, 2025
(Think of UPI, wallets and merchants.)
Before we jump into designing a transaction system, let’s quickly understand what idempotency means.
🔹 What is Idempotency?
Duplicate request? Idempotency means:
“Bhai, already ho gaya, chill maar.”
Imagine this:
You hit “Pay ₹100”
App shows network error
You hit “Pay” again
Without idempotency → ₹200 gets debited.With it → System says:
“Same txn ID hai boss, already done. Chill.”Result? One clean payment, no double debits.
Now lets come to its components:
Flow Diagram:

🔹 API Gateway—The Waiter of Your System
API Gateway is your app’s front guy. Instead of mobile app talking to 10 services, it just talks to one.
Socho ek restaurant hai 🍽️:
You:
“Butter chicken, naan, ek lassi.”
Waiter (API Gateway):
Samajh gaya
Kitchen ke alag-alag chefs ko instructions di
Sab laake plate mein serve kar diya
That’s exactly how API Gateway works.
🔹 Transaction Service—Payment Ka Control Room 🚦
This guy is the mastermind.
It doesn’t directly move money.
doesn’t write to DBs,
but it does create a transaction ID
and orchestrates everything else.
Socho:
Alice pays ₹100 to Bob
Transaction Service says:
“ID banao, balance check karo, fraud dekh lo, idempotency thikh hai? Toh bhai, chalo aage 🚀”.”
Payment wallet se ho ya UPI se, it just says:
“Plug a new method, implement karo, kaam ho gaya 💥”
Aaj UPI, kal Crypto—no code change.
🔐 Alright, but where do we store these transaction IDs safely and quickly?
PostgreSQL? SQL? Redis?
👉 Use Redis.
Why?
In-memory hai which means super fast
High load mein chhoti-chhoti checks chahiye
Redis is fast, light, and perfect for quick checks.
“Har kaam DB se karwana zaroori nahi — Redis hai apna chhota bhai: tez, sasta, aur har waqt standby.”
But wait—Redis keys expire (5 min TTL)? Toh, we will have a two-layer check:
Check Redis
Not there? Check Postgres
Found? Reuse old txn result
🔹 Wallet Service—Balance Ka Boss
Handles top-up, debit, and refund.
Flow:
The user pays ₹100
Transaction → Wallet: debit ₹100
Wallet → Kafka: “Debit Alice, Credit Merchant.” (Kafka here to log events)
Ledger logs it (think of Ledger as book of records)
Wallet confirms and updates Redis
Note: Wallet never blindly updates balance. Ledger confirmation is a must.
Wallet Service bina Ledger ki confirmation ke kuch nahi karta—boss ka order chahiye har baar.
🔹 UPI Service—Ek Callback Aur Game Palat Gaya 🎬💥
“Yahan callback ka scene filmy hai boss — ek late response, aur pura game ulta.”
UPI collect/pay ke liye bank se baat karta hai.
Flow:
Transaction triggers UPI collect
The bank takes 3–10 sec to reply
Success? Ledger gets: debit Alice, credit Bob
Transaction marked as SUCCESS
Also handles timeouts, retries, and duplicate callbacks
💥 But What If It Fails?—Callback and Side Effects 🎭
UPI is async by nature, and callback timing decides everything.Kabhi pehle timeout ho jaata hai, aur baad mein callback aata hai.Matlab: “Interval ke baad hero entry, par tab tak climax khatam!”
Here are 2 common real-life fail scenes the system must handle:
❌ 1. Callback Never Came (Timeout)
Problem: Bank never responds
Effect: Transaction stuck in “Pending”
Fix: Use background reconciliation jobs
“Bank chup… system wait karta raha… transaction bas latak gaya 😵”
🕰️ 2. Success Callback After Retry
Problem: You retried assuming failure, but original success callback arrives later
Effect: Double debit or wrong status
Fix: Always check txn status before acting
“Retry ke baad asli callback aaya, lekin system already move on kar chuka tha 💔”
🔹 Merchant Service—Fee Lagao, Route Batao, Paisa Sambhalo💼
This service is the backend ka dukandar — quietly managing merchant money, fees, and where the payment should go.
Maps QR to wallet/UPI
Decides routing (wallet vs UPI)
Applies platform fee (e.g. 2%)
Example:
₹100 paid to merchant
The merchant gets ₹98, and the Platform gets ₹2
Ledger logs both
Later, ₹98 goes to the merchant bank via settlement.
🔹 Ledger Service—Jahan Sab Likha Jaata Hai 📒
The single source of financial truth. Every money movement is logged here.
You can visualise this as a double-entry system: one debit and one credit, always in sync.
Kafka helps:
✅ Transaction Service publishes to ledger-events topic✅ Ledger reads the event and writes two entries✅ Wallet optionally listens and updates balance
Even if services crash → Kafka ensures no loss.
🧩 Transaction Flow With Kafka-Backed Ledger
Let’s walk through an example:
User A pays ₹100 to User B
🔁 Step-by-Step
Transaction Service publishes a ledger event:

➤ This message is published to a Kafka topic: ledger-events
2. Ledger Service subscribes to ledger-events topic
It reads the event
Validates and processes it
Writes two records into the ledger database:
Debit for Alice
Credit for Bob
3. Wallet Service (optional) subscribes too:
Updates real-time balances in Redis or DB
Sends notifications, etc.
🔐 Why Kafka?
Events are stored even if services crash
Can handle thousands of transactions/sec
You can replay ledger events to rebuild state
🔄 Retry & Fault Tolerance
If writing to DB fails (e.g., the ledger DB is down), Kafka will keep retrying until it succeeds.
The ledger consumer can track offsets—so no event is lost or processed twice.
Visual Example:

🔹 Settlement Service — Real Paisa Transfer Yahan Se
“Yahan asli paisa move hota hai—not just system ke numbers, but actual INR 💸”
Every hour/night:
Service picks all merchant credits
Net payout calculated (after fees)
₹50,000 credit? → ₹49,500 gets transferred
Bank API (NEFT/IMPS/RTGS) used
Ledger updated → marked as settled
Retry later or alert ops — but never mark as settled until bank confirms. 💼
⚠️ What If Settlement Fails?
Let’s say the NEFT request failed due to invalid IFSC.
The service should:
Mark that payout as FAILED
Retry after some interval (or alert ops team)
Never mark the ledger entries as “settled” until bank confirms success
This was a high-level breakdown of how real-time transaction systems like Google Pay work under the hood. Want me to dive into any specific part deeper? Drop a comment below!
🚀 Follow for more such backend breakdowns!
For references:


Comments