LLD Hub
lldstrategychain-of-responsibilityobserver

How to Design a Payment Gateway | LLD Interview Guide

Design a payment processing system with idempotency, multiple payment methods, fraud detection hooks, and webhook notifications. Core topic at Razorpay, PayU.

12 April 2025·10 min read

Practice this problem

Payment Gateway — get AI-scored feedback on your solution

Solve it →

Designing a Payment Gateway is a core LLD topic at Razorpay, PayU, PhonePe, Paytm, and any fintech company. It requires understanding idempotency, multi-method payment processing, fraud detection, and webhook reliability. Here's a complete design.

Core Entities

  • Payment — idempotencyKey, amount, currency, status, method
  • Transaction — maps to a payment provider's transaction
  • PaymentMethod — Card, UPI, NetBanking, Wallet
  • Refund — references original Payment, amount, reason
  • Webhook — event type, payload, delivery status
  • FraudCheck — result of fraud detection pipeline

Idempotency — Most Critical Concept

class PaymentService {
  processPayment(request: PaymentRequest): Payment {
    // Check if this idempotency key was already processed
    const existing = this.paymentRepo.findByIdempotencyKey(request.idempotencyKey);
    if (existing) return existing; // Return same result, don't charge again

    const payment = new Payment(request);
    this.paymentRepo.save(payment);

    // Process through fraud checks and payment provider
    const fraudResult = this.fraudPipeline.check(request);
    if (fraudResult.rejected) {
      payment.fail("FRAUD_DETECTED");
      return payment;
    }

    const result = this.getProvider(request.method).charge(payment);
    payment.updateFromProviderResult(result);
    this.webhookService.dispatch(payment);
    return payment;
  }
}

Strategy for Payment Methods

interface PaymentProvider {
  charge(payment: Payment): ProviderResult;
  refund(transaction: Transaction, amount: number): RefundResult;
}
class RazorpayCardProvider implements PaymentProvider { ... }
class UPIProvider            implements PaymentProvider { ... }
class WalletProvider         implements PaymentProvider { ... }

Chain of Responsibility for Fraud Detection

abstract class FraudCheck {
  protected next: FraudCheck | null = null;
  setNext(c: FraudCheck) { this.next = c; return c; }
  abstract check(req: PaymentRequest): FraudResult;
}
class VelocityCheck extends FraudCheck {
  check(req) {
    const recent = this.txRepo.countInLastHour(req.userId);
    if (recent > 10) return FraudResult.reject("TOO_MANY_ATTEMPTS");
    return this.next?.check(req) ?? FraudResult.pass();
  }
}
class AmountAnomalyCheck extends FraudCheck { ... }
class GeoMismatchCheck   extends FraudCheck { ... }

Webhook Reliability

class WebhookService {
  dispatch(payment: Payment) {
    const event = new WebhookEvent("payment.captured", payment);
    const merchants = this.merchantRepo.getSubscribed(payment.merchantId);
    merchants.forEach(m => this.deliverWithRetry(m.webhookUrl, event));
  }
  private async deliverWithRetry(url: string, event: WebhookEvent, attempt = 0) {
    const success = await this.httpClient.post(url, event);
    if (!success && attempt < 5)
      setTimeout(() => this.deliverWithRetry(url, event, attempt + 1),
        Math.pow(2, attempt) * 1000);
  }
}

Ready to practice?

Submit your solution and get AI-scored feedback on OOP, SOLID principles, design patterns, and code quality.

Solve Payment Gateway