Blog 4 — Stripe: How We Build Idempotent APIs

C

Qubits of DPK

March 21, 2026

Core Case Studies
Core Concept: Idempotency keys, Distributed transaction safety, Payment retry safety
Why SDE-2 Critical: Extremely relevant for Razorpay, PhonePe, PayU, Flipkart interviews
Status: Draft notes ready

Quick Revision

  • Problem: Network retries can create duplicate payments.
  • Core pattern: Client-generated idempotency keys with cached server responses.
  • Interview one-liner: Safe retries come from idempotent APIs, not from perfect networks.

️ The Core Problem

javascript
QUBITS OF DPK
1User clicks "Pay ₹500"
234Request sent to Stripe
56  Network timeout  (did it go through?)
78User clicks "Pay ₹500" again
910Was user charged ₹500 or ₹1000?
Without idempotency → charged TWICE
With idempotency → charged ONCE

Core Concepts

What is Idempotency?

  • An operation is idempotent if calling it multiple times produces the same result as calling it once
  • HTTP GET is naturally idempotent (reading doesn't change data)
  • HTTP POST is NOT naturally idempotent (each call creates a new record)

Stripe's Idempotency Key Solution

javascript
QUBITS OF DPK
1Client generates a unique key: "pay_user123_order456_1710000000"
2
3First request:
4  POST /charges
5  Idempotency-Key: pay_user123_order456_1710000000
6Stripe processes payment → stores result against key → returns success
7
8Retry request (same key):
9  POST /charges
10  Idempotency-Key: pay_user123_order456_1710000000
11Stripe finds key in DB → returns SAME result as before → no duplicate charge

How Stripe Stores Idempotency Keys

javascript
QUBITS OF DPK
1idempotency_keys table:
2  key        → "pay_user123_order456_1710000000"
3  response   → {"status": "succeeded", "charge_id": "ch_abc"}
4  created_at → 2024-01-01 10:00:00
5  expires_at → 2024-01-25 10:00:00  (24 hours retention)
  • Key lookup happens BEFORE processing
  • If key exists → return cached response immediately
  • If key doesn't exist → process → store result → return

Distributed Transaction Safety

javascript
QUBITS OF DPK
1Payment flow involves:
2  1. Charge customer card
3  2. Update order status
4  3. Send confirmation email
5  4. Update inventory
6
7If step 3 fails → do you refund? Retry from step 3?
8
9Stripe's approach: Each step is idempotent + uses saga pattern
10Each step can be safely retried
11Compensating transactions for rollback

Why This Matters at Scale

5 Interview Questions This Blog Unlocks

Q1. Design a payment system that handles retries safely

Answer: Client generates idempotency key (userId + orderId + timestamp). Server checks key before processing. If key exists → return cached result. If not → process → store key + result atomically → return. Key expires after 24 hours.

Q2. What is idempotency and why is it critical for payment APIs?

Answer: Idempotency means the same request produces the same result regardless of how many times it's called. Critical for payments because networks are unreliable — clients must retry safely without double-charging users.

Q3. How would you generate a good idempotency key?

Answer: Combine: userId + orderId + amount + timestamp. Must be unique per operation, deterministic on retry (same client generates same key for same operation), and have bounded TTL to prevent unbounded storage growth.

Q4. What is the difference between idempotency and at-least-once vs exactly-once delivery?

Answer: At-least-once = message delivered minimum once, possibly more. Exactly-once = delivered exactly once (very expensive). Idempotency makes at-least-once SAFE — even if processed multiple times, result is same. Most systems use at-least-once + idempotent consumers.

Q5. How does Stripe handle partial failures in a multi-step payment flow?

Answer: Saga pattern — each step is a local transaction with a compensating transaction (refund, cancel, etc.). If step 3 fails, compensating transactions undo steps 1 and 2. Each step is idempotent so retries are safe.

Key Engineering Lessons