AceTheOffer
Case StudiesAdvanced

Design a Payment System

Practice a payment-system design with idempotency, ledgers, processor integration, reconciliation, failure states, security, and multi-region tradeoffs.

14 min readUpdated August 22, 2026

What you'll learn

Run the architecture drill

  • How to model payment intent, attempt, ledger entry, and external processor result separately.
  • Why idempotency and reconciliation are essential after any timeout or callback gap.
  • How to discuss security, reliability, and multi-region considerations without overclaiming guarantees.

A payment system is not a request that returns success after calling a processor. It is a correctness system that must preserve intent, prevent duplicate charges, represent uncertain outcomes, reconcile external records, and provide an auditable source of truth when every dependency is behaving imperfectly.

Start with the architecture drill, then follow the request path through scale, failure, and a defensible interview answer.

Interview reasoning

Make your assumptions and decision path easy to inspect.

ATOFF architecture reasoning canvas

Design a Payment System: the architecture drill

Short answer

A payment system protects money movement by separating customer intent, internal accounting truth, processor uncertainty, and reconciliation into durable state transitions.

10× evolution

Isolate ledger writes from processor throughput without weakening reconciliation.

3 checkpoints
  1. 01

    Decision checkpoint

    Design brief

    Create an idempotent payment intent before contacting a processor so a client retry can recover the same operation rather than create another charge.

  2. 02

    Decision checkpoint

    First request path

    Represent debits, credits, holds, and reversals as immutable accounting entries; processor responses are evidence to reconcile, not the only record.

  3. 03

    Decision checkpoint

    Failure drill

    A timeout after submission is pending, not failed; reconcile through provider events and queries before allowing a duplicate attempt.

Say it in the interview

I would make the payment intent idempotent, preserve an immutable ledger, and reconcile every unknown processor outcome before changing customer-visible balance.

  1. 1

    Client idempotency key

    create or retry: Payment API intent state

  2. 2

    Payment API intent state

    record intent: Append-oriented ledger · attempt charge: External processor · initial response: Merchant-visible payment state

  3. 3

    Append-oriented ledger

    confirmed or pending: Merchant-visible payment state

  4. 4

    External processor

    async outcome: Processor event + reconciliation

  5. 5

    Processor event + reconciliation

    match + append fact: Append-oriented ledger

  6. 6

    Merchant-visible payment state

Payment lifecycle: durable intent, uncertain processor, reconciled truth. The client creates one idempotent intent. The service records the business fact before an external processor attempt, then uses asynchronous processor events and reconciliation to make the ledger converge on the observed outcome.
  1. Client idempotency key flows to Payment API intent state via create or retry.
  2. Payment API intent state flows to Append-oriented ledger via record intent.
  3. Payment API intent state flows to External processor via attempt charge.
  4. External processor flows to Processor event + reconciliation via async outcome.
  5. Processor event + reconciliation flows to Append-oriented ledger via match + append fact.
  6. Append-oriented ledger flows to Merchant-visible payment state via confirmed or pending.
  7. Payment API intent state flows to Merchant-visible payment state via initial response.

Walk the design under pressure

Start with monetary invariants and the payment lifecycle

Clarify whether the system authorizes, captures, refunds, transfers, or simply orchestrates a third-party processor. Define the currency, settlement, compliance boundary, and what success means to the merchant and customer. The architecture changes dramatically when the platform itself holds funds versus when it records processor outcomes.

Model payment intent, processor attempt, ledger entry, and refund as distinct durable records. An idempotency key belongs to the client-visible intent; it should make retrying the same action return the same logical result rather than creating a second charge.

Use an append-oriented ledger for facts, not mutable balance guesses

A ledger records balanced, immutable facts that can be audited and reconciled. A current balance may be a projection derived from those facts, but it should not be the only record of how money moved. This separation makes correction and investigation possible without rewriting history.

A transactional primary store is a natural source of truth for intent and ledger state. Other views—customer history, risk signals, receipts, analytics—can be built asynchronously if their lag does not decide whether money is moved.

Timeouts create an unknown outcome, not a failed payment

A processor call can time out after the processor has accepted the charge. Retrying without the same idempotency identity can duplicate it. Record an in-progress state, query or await processor evidence, accept signed callbacks where appropriate, and reconcile the external record against the internal intent before telling the customer a final result.

Do not collapse pending, failed, reversed, and confirmed states into one boolean. Each state has a different user message, retry policy, financial consequence, and support path.

Staff-level insight: recovery, security, and auditability are the architecture

At staff scope, define reconciliation cadence, exception queues, manual review controls, immutable audit access, key management, least-privilege integration, and incident procedures that never trade financial correctness for superficial availability. Multi-region design must avoid two writers independently deciding the same financial fact.

In an interview, make the tradeoff explicit: preserve intent and show a pending state during uncertainty, then reconcile. That is stronger than promising an impossible exactly-once network call.

Keep this with you

Key takeaways

  • Payments require durable intent, idempotency, a ledger, and reconciliation—not a single success flag.
  • A timeout is an uncertain state that must be resolved from evidence before retrying or confirming.
  • Security, auditability, and controlled recovery are core system-design requirements.

Practice aloud

Interview questions to explore

  1. 1.How do you prevent a double charge after a client retry?
  2. 2.What data is authoritative when your system and the processor disagree?
  3. 3.How do you communicate a payment that is still being reconciled?

Common follow-ups

Frequently asked questions

Can a payment API guarantee exactly-once charging?

A network call alone cannot. The design uses stable idempotency identities, durable intent, processor-side deduplication where available, and reconciliation to make repeated attempts converge on one logical payment.

Why is a ledger needed if a processor stores transactions?

A platform still needs its own auditable record of business intent, state transitions, fees, refunds, and reconciliation decisions. The processor record is important evidence but not always the entire business truth.

Already an Elite member? Open the complete walkthrough.

Need the broader preparation context? Go back to Interview Preparation for behavioral readiness, question practice, and the larger AceTheOffer preparation framework.

Keep exploring

Back to the System Design guideBack to Interview Preparation

Keep building momentum

Popular Career Resources