Design a Payment Processor
What is the Payment Processor Problem?
Section titled “What is the Payment Processor Problem?”Design a payment processor system that supports multiple payment methods (credit card, PayPal, bank transfer), manages transaction states, ensures idempotency to prevent duplicate charges, and implements retry logic for handling transient failures. The system should handle concurrent transactions safely and be extensible for adding new payment methods.
In this problem, you’ll design a secure orchestration layer that coordinates between your application and various 3rd-party providers while maintaining a strict audit trail and absolute consistency.
Problem Overview
Section titled “Problem Overview”Design a robust backend system that accepts payment requests, routes them to the correct provider, and ensures the transaction reaches a final state accurately.
Core Requirements
Section titled “Core Requirements”Functional Requirements:
- Multi-method Support: Process Credit Cards, PayPal, and Bank Transfers.
- State Management: Track transactions through Pending, Completed, and Failed states.
- Idempotency: Prevent double-charging using unique idempotency keys.
- Retries: Automatically retry transient failures with backoff.
- Refunds: Support full and partial refunds for completed transactions.
- Audit Logging: Maintain a permanent record of every state change.
Non-Functional Requirements:
- Absolute Consistency: No race conditions in state transitions.
- Security: Sensitive data should never be logged or stored long-term.
- Availability: The system must stay responsive even if one provider is down.
- Extensibility: Easy to add new strategies (like Apple Pay or Crypto).
What’s Expected?
Section titled “What’s Expected?”1. System Architecture
Section titled “1. System Architecture”The processor acts as a secure buffer between the CheckoutService and external ProviderAPIs.
2. Key Classes to Design
Section titled “2. Key Classes to Design”classDiagram
class PaymentProcessor {
-Map~String, Transaction~ cache
-ProviderFactory providers
+execute(request)
}
class Transaction {
-String id
-String idempotencyKey
-double amount
-TransactionState state
+transition(nextState)
}
class TransactionState {
<<interface>>
+handle()
}
class PaymentProvider {
<<interface>>
+authorize(amount)
+capture(amount)
}
PaymentProcessor --> Transaction
Transaction --> TransactionState
PaymentProcessor --> PaymentProvider
System Flow
Section titled “System Flow”Idempotent Payment Flow
Section titled “Idempotent Payment Flow”Key Design Challenges
Section titled “Key Design Challenges”1. Implementing Idempotency
Section titled “1. Implementing Idempotency”If a user clicks “Pay” and the network times out, the mobile app might retry. You cannot charge them twice.
Solution: Use an Idempotency Key (usually a UUID generated by the client). Before processing, the PaymentProcessor checks the database for that key. If found, it returns the previous result instead of starting a new transaction.
2. Handling Provider Failures
Section titled “2. Handling Provider Failures”What if Stripe is down for 5 seconds?
Solution: Use the Command Pattern with Retry Logic. Queue the payment request. If the provider returns a “503 Service Unavailable,” the system uses an exponential backoff strategy to retry. If it returns a “402 Card Declined,” do NOT retry—this is a permanent failure.
3. The Distributed State Problem
Section titled “3. The Distributed State Problem”A transaction might be “Authorized” in Stripe but your database fails to update.
Solution: Webhooks & Reconciliation. Implement a background “Reconciliation Job” that polls the provider’s API for any “Authorized” payments that don’t have a matching “Completed” state in your DB, ensuring the two systems eventually reach consistency.
What You’ll Learn
Section titled “What You’ll Learn”By solving this problem, you’ll master:
- ✅ Idempotency Mechanisms - Building bulletproof distributed logic.
- ✅ State Machines - Handling non-linear lifecycles (Refunds, Chargebacks).
- ✅ Strategy & Factory Patterns - Abstracting away complex third-party SDKs.
- ✅ Financial Reliability - Designing for zero-data-loss scenarios.
View Complete Solution & Practice
Section titled “View Complete Solution & Practice”Ready to see the full implementation? Open the interactive playground to access:
- 🎯 Step-by-step guidance through the 8-step LLD approach
- 📊 Interactive UML builder to visualize your design
- 💻 Complete Code Solutions in Python, Java, C++, TypeScript, JavaScript, C#
- 🤖 AI-powered review of your design and code
Related Problems
Section titled “Related Problems”After mastering the Payment Processor, try these similar problems:
- ATM System - Physical state machines and bank communication.
- Online Shopping Cart - The “frontend” to the payment system.
- Notification Service - Alerting users of payment successes/failures.