How to pass the Paytm SDE-2 low-level design interview

Paytm's backend handles a massive volume of mission-critical financial transactions every single day. If you're interviewing for a Software Development Engineer 2 (SDE-2) role, the Low-Level Design (LLD) round is your chance to prove you can turn complex business logic into thread-safe, resilient code. Interviewers aren't just looking for clean object-oriented principles. You need to show a deep grasp of concurrency, database isolation, and fault tolerance. The most notorious hurdle in this specific round? Designing a multi-wallet ledger system. We'll walk through the exact technical depth you need to clear this interview, covering everything from immutable ledgers to deadlock prevention.
The Paytm SDE-2 Interview Process
Before we tackle the technical solution, let's look at where the LLD round actually sits in the broader hiring pipeline. Paytm's interview loop for mid-level engineers is notoriously rigorous. They heavily weight practical engineering skills over abstract theoretical puzzles.
| Interview Round | Focus Area | Typical Duration |
|---|---|---|
| Data Structures & Algorithms | Problem-solving, arrays, trees, dynamic programming, time complexity. | 60 minutes |
| Low-Level Design (Machine Coding) | Object-oriented design, concurrency, DB schemas, API design. | 90 to 120 minutes |
| High-Level Design | Distributed systems, scalability, microservices, database selection. | 60 minutes |
| Hiring Manager | Behavioral questions, past project deep-dives, culture fit. | 45 to 60 minutes |
The Challenge: Designing a Multi-Wallet System

The core problem statement usually goes something like this: design a system where users can create multiple wallets, fund them from a bank account, and transfer money to other users. Your system has to be highly concurrent, strictly consistent (meaning absolutely no negative balances or magically created money), and idempotent to handle network retries gracefully. As an SDE-2 candidate, your interviewer is watching closely. Do you immediately start typing code, or do you take a step back to define a robust domain model first?
What are the core entities for a wallet ledger?
Candidates often make the mistake of treating a wallet balance as a simple mutable variable. In any financial system, you have to implement double-entry bookkeeping. Money is never just created or destroyed; it moves from one ledger to another. To model this correctly, you'll need four primary entities.
- User: Represents the customer holding the accounts.
- Wallet: The container for funds, which holds a cached balance for fast reads.
- Transaction: Represents the intent to move funds (like a Transfer, Deposit, or Withdrawal) alongside a unique idempotency key.
- LedgerEntry: The immutable record of a specific credit or debit to a wallet. Every transaction generates at least two ledger entries—one debit and one credit.
How do you prevent double-spending in concurrent transactions?
When two requests try to deduct money from the same wallet at the exact same time, a race condition can easily push the balance below zero. To fix this, you have to talk about database concurrency control. You generally have two main options here: Optimistic Locking and Pessimistic Locking.
Optimistic locking relies on a version column on the Wallet row. When a transaction updates the balance, it verifies that the version matches what it initially read. If it doesn't match, the transaction fails and retries. This approach is incredibly fast for read-heavy systems, but it can trigger high contention and retry exhaustion during massive traffic spikes like a flash sale. Pessimistic locking, on the other hand, uses a database-level lock (like SELECT ... FOR UPDATE). This stops other transactions from reading or modifying the locked row until the current transaction commits. For financial ledgers operating at Paytm's scale, pessimistic locking is usually the preferred choice for balance deductions. It guarantees strict serialization and spares you from building complex retry logic in the application layer.
How do you handle deadlocks when transferring between wallets?
If you go with pessimistic locking, the interviewer will inevitably ask about deadlocks. Imagine Thread A transfers money from Wallet X to Wallet Y. Thread A locks Wallet X and waits for Wallet Y. At the same time, Thread B transfers money from Wallet Y to Wallet X. Thread B locks Wallet Y and waits for Wallet X. Now you have a deadlock, and the database will eventually step in and kill one of the transactions.
The cleanest solution is deterministic lock ordering. You have to acquire locks in a globally consistent order every single time. Before locking the rows, simply sort the wallet IDs. For example, if Wallet X has ID 100 and Wallet Y has ID 200, both Thread A and Thread B will try to lock Wallet X first, and then Wallet Y. This completely wipes out the cyclic dependency that triggers deadlocks. Breaking this concept down clearly will massively boost your credibility in the LLD round.
How do you make the transaction API idempotent?
Network timeouts happen all the time in distributed systems. If a user's mobile app sends a transfer request but drops the connection before getting a response, the app is going to retry. If your system isn't idempotent, you'll end up deducting the money twice. You have to design an API that handles these retries safely.
You pull this off by forcing the client to send a unique Idempotency-Key header (usually a UUID) with every single state-mutating request. Over in your database, you can create an IdempotencyRecord table or just add a unique constraint on the idempotency_key column inside your Transaction table. When a request hits the backend, you try to insert the key. If you hit a unique constraint violation, you instantly know it's a retry. From there, you just fetch the existing transaction status and hand it back to the client without running the financial logic a second time.
Implementing the State Transitions
During the actual machine coding phase, you'll need to translate these concepts into working classes. A solid strategy is to build a WalletService that handles the orchestration. This service should wrap the entire transfer operation inside a single database transaction to maintain strict ACID properties. If you're writing in Java, you'd typically leverage the @Transactional annotation here.
- Step 1: Validate the input parameters and the idempotency key.
- Step 2: Sort the source and destination wallet IDs to prevent deadlocks.
- Step 3: Acquire pessimistic locks on both wallet rows in the sorted order.
- Step 4: Check if the source wallet has sufficient funds. If not, rollback and throw an InsufficientFundsException.
- Step 5: Deduct the amount from the source wallet balance and add it to the destination wallet balance.
- Step 6: Insert two immutable LedgerEntry records (one debit, one credit) linking to a new Transaction record.
- Step 7: Commit the database transaction.
By structuring your code exactly like this, you prove to the interviewer that you know how to build resilient systems that can survive a server crash right in the middle of execution.
How to Ace Your Paytm LLD Round Live with AcePrompt AI
Mastering concurrent ledger design is tough, especially when you're trying to recall lock ordering and isolation levels while an interviewer watches your screen. Studying guides is definitely essential, but having real-time support during your actual interview can easily be the difference between a quick rejection and an SDE-2 offer.
AcePrompt AI operates as your silent, real-time interview copilot. It securely listens to the interviewer's prompts and instantly surfaces structured, highly technical talking points right on your screen. If the interviewer suddenly pivots and asks about database sharding for the wallet system, AcePrompt instantly feeds you the trade-offs between hash-based sharding and directory-based sharding, keeping you articulate and confident.
Frequently asked questions
Is the Paytm LLD round purely coding or mostly design?
It's a solid mix of both, which is why people often call it 'machine coding'. You're expected to design the class structure and database schema, and then actually write working, compilable code for the core business logic—all within a pretty tight timeframe.
Can I use any programming language for the LLD round?
Yes, Paytm generally lets you use your preferred language, whether that's Java, Python, C++, or Go. That said, Java is incredibly prevalent in their backend stack. Demonstrating real proficiency with Java concurrency and Spring Boot can definitely give you an edge.
Do I need to write a working database connection during the interview?
Usually, no. Interviewers fully expect you to simulate the database layer using in-memory data structures like ConcurrentHashMap. You still have to design the interfaces, though, and explain exactly how your concurrency controls would translate to a real relational database.
How important are design patterns in this round?
Extremely important. Applying patterns like Strategy for handling different payment methods, Factory for creating transaction objects, and Singleton for the ledger service shows real maturity in your software engineering skills.
What is the difference between LLD and HLD at Paytm?
LLD focuses heavily on the internal structure of a single application, meaning your classes, interfaces, DB schemas, and thread safety. HLD zooms out to look at the architecture of the entire system, covering microservices, load balancers, caching layers, and distributed databases.
Related comparisons
See AcePrompt in action
Watch how AcePrompt supports a real technical round - structured answers, tuned to your resume, in real time.
Nail your Paytm SDE-2 interview with real-time AI guidance from AcePrompt.
Get started