💳
E-Commerce & Payments

Payment Gateway

Idempotency Aur Multiple Providers
💡 Payment gateway EK BHAROSEMAND DAAKIYA hai. Sabse badi zimmedaari ye hai ki agar tumne ek hi chithi do baar de di, to wo do baar deliver NA kare. Ek galti = customer ka do baar paisa katna.

Sabse important concept IDEMPOTENCY hai. Network timeout par client retry karega — us waqt SAME idempotency key ke saath aayi request DOBARA charge nahi honi chahiye, pehle waale ka result return hona chahiye. Ye batana is problem ka core hai.

Multiple providers (Razorpay, Stripe, PayPal) ke liye PaymentProvider interface banao aur runtime par choose karo. Payment status ek State machine hai: INITIATED → PENDING → SUCCESS/FAILED → REFUNDED. Aur webhooks zaroor mention karo — payment async complete hoti hai, isliye provider callback bhejta hai aur wo callback bhi idempotent hona chahiye.

interface PaymentProvider {
  PaymentResult charge(PaymentRequest req);
  RefundResult refund(String txnId, Money amount);
}

class PaymentService {
  PaymentResult pay(PaymentRequest req) {
    // Idempotency: same key = same result, dobara charge NAHI
    var existing = repo.findByIdempotencyKey(req.getIdempotencyKey());
    if (existing.isPresent()) return existing.get().toResult();

    var provider = providerFactory.select(req.getMethod());
    var result = provider.charge(req);
    repo.save(req.getIdempotencyKey(), result);
    return result;
  }
}
💳
Payment gateway EK BHAROSEMAND DAAKIYA hai. Sabse badi zimmedaari ye hai ki agar tumne ek hi chithi do baar de di, to wo do baar deliver NA kare. Ek galti = customer ka do baar paisa katna.
1 / 2
⚡ Quick Recap
  • Idempotency key sabse important — retry par double charge kabhi nahi
  • PaymentProvider interface se multiple gateways plug karo
  • Status ek state machine hai; webhooks async aur duplicate aate hain
Is page mein (2 subtopics)

Client har payment attempt ke liye ek UNIQUE key generate karta hai (aksar orderId + attempt). Server us key ko result ke saath store karta hai. Wahi key dobara aaye to STORED result return hota hai, naya charge nahi.

Ek subtle case: request beech mein hai aur wahi key dobara aa gayi. Iske liye key ko "IN_PROGRESS" mark karo aur duplicate ko wait ya reject karao — warna do parallel charges ho sakte hain.

enum IdempotencyStatus { IN_PROGRESS, COMPLETED }

PaymentResult pay(PaymentRequest req) {
  var claimed = repo.claim(req.getIdempotencyKey(), IN_PROGRESS);
  if (!claimed) {
    var existing = repo.find(req.getIdempotencyKey());
    if (existing.status() == COMPLETED) return existing.result();
    throw new PaymentInProgressException();   // duplicate parallel request
  }
  // ... actual charge, phir COMPLETED mark
}

Payment async hoti hai — provider baad mein webhook bhejta hai. Webhook AT-LEAST-ONCE hota hai, matlab same event kai baar aa sakta hai. Har webhook ka eventId store karo aur duplicate ignore karo.

Webhook kabhi kabhi aata hi nahi (network issue). Isliye RECONCILIATION job zaroori hai — PENDING payments ko periodically provider se query karke status update karo. Ye batana production maturity dikhata hai.

💡Tip: Webhook signature verify karna security requirement hai — bina verification ke koi bhi fake "payment success" bhej sakta hai.