04QuestionsPayment system

04 · Worked prompt

Payment system

Design payment intents, idempotency, ledgers, authorization, settlement, reconciliation, and webhooks.
45 minInterview blueprint
INTERVIEW RUBRIC

What a passing answer must show

100 points · 45 minutes

  1. 20pts

    Scope the problem

    0–5 min

    Prioritize the core flows, state the scale, and name the non-goals.

  2. 15pts

    Define contracts

    5–10 min

    Identify durable entities, APIs, idempotency, and the source of truth.

  3. 30pts

    Complete the diagram

    10–25 min

    Trace one write path and one read path. Label the commit boundary and async work.

  4. 20pts

    Lead one deep dive

    25–38 min

    Choose the highest-risk trade-off and explain the mechanism, alternative, and cost.

  5. 15pts

    Prove reliability

    38–45 min

    Walk a failure, recovery, metric, bottleneck, and evolution path.

DRAW THIS FIRST

One complete box-and-arrow design

Design payment intents, idempotency, ledgers, authorization, settlement, reconciliation, and webhooks.

Payment system · system architecture
Payment system system architecture. The internal ledger is exact; processor outcomes are idempotent, versioned, and reconciled asynchronously. Request path: Merchant clients to Payments API to Payment orchestrator to Payment + ledger DB. Asynchronous path: Transactional outbox to Reconciliation workers. Read path: Payment status API to Settlement view. External dependency: Payment processor. Delivery path: Webhook delivery.

Write

Merchant clients enters through Payments API. Payment orchestrator owns validation and commits the durable record to Payment + ledger DB.

Propagate

Transactional outbox separates the committed write from background work. Reconciliation workers can retry safely while it builds Settlement view.

Read

Payment status API serves from Settlement view, then checks authoritative state whenever freshness, policy, or correctness requires it. It also consults Payment processor as an explicit dependency.

Say this first: The internal ledger is exact; processor outcomes are idempotent, versioned, and reconciled asynchronously.

Open the full whiteboard ↗
DEFEND THE DIAGRAM

Explain every boundary before adding more boxes.

The internal ledger is exact; processor outcomes are idempotent, versioned, and reconciled asynchronously.

INTERVIEW CONTRACT

Design payment intents, idempotency, ledgers, authorization, settlement, reconciliation, and webhooks.

CAPACITY QUESTIONS TO QUANTIFY

Exact money · asynchronous rails · zero duplicate charges · long audit retention. State average and peak load, stored bytes, bandwidth or open connections, and the growth horizon before choosing a partitioning strategy.

01

End-to-end walkthrough

Trace the architecture in this order.

  1. 01
    Enter and classify the request
    Merchant clients → Payments API

    Create, capture, refund enters over HTTPS / RPC. Payments API handles identity, admission, routing, and request context; it deliberately does not own domain truth.

  2. 02
    Validate, then cross the commit boundary
    Payments API → Payment orchestrator → Payment + ledger DB

    Payment orchestrator receives the idempotent command, checks invariants and retry identity, then uses ACID + outbox to update Payment + ledger DB. The user-visible mutation is accepted only after this boundary succeeds.

  3. 03
    Move replayable work off the request path
    Payment orchestrator → Transactional outbox → Reconciliation workers → Settlement view

    Payment orchestrator emits publish after commit; Reconciliation workers uses consume and project / update to build Settlement view. Consumers must tolerate duplicate delivery and stale retries because this path is asynchronous.

  4. 04
    Serve reads from the right authority
    Payments API → Payment status API → Settlement view / Payment + ledger DB

    Payment status API uses optimized read for the common, read-optimized path and strong read when correctness or repair requires authoritative state. The API must state the freshness promise instead of hiding it.

  5. 05
    Contain the dependency boundary
    Payment orchestrator → Payment processor

    stable provider ref crosses into Payment processor. Treat timeouts as ambiguous, use a deadline and idempotent retry or reconciliation, and keep the core state recoverable when the dependency is unavailable.

  6. 06
    Deliver without changing the source of truth
    Reconciliation workers → Webhook delivery → Merchant clients

    Reconciliation workers uses signed webhook; Webhook delivery returns updates over stream / push. Sequence IDs, reconnect cursors, and backpressure make delivery resumable without turning a socket into durable state.

02

Ownership ledger

Why each box exists—and what it must defend.

ComponentOwnsWhy it existsInterviewer probe
Payments APIAuth + idempotency scopeIdentity, admission, routingProtects the system edge and attaches trusted context before domain work begins.Timeout budgets, quotas, regional routing
Payment orchestratorState machine + provider callWrite invariants and retry identitySerializes or conditionally applies state changes before acknowledging success.Concurrent writes, deduplication, hot ownership
Payment + ledger DBIntent and balanced entriesAuthoritative durable stateProvides the one record used to resolve disputes, recover, and rebuild projections.Partition key, replication, consistency
Transactional outboxCommitted merchant eventsDurable asynchronous handoffAbsorbs bursts and lets slow or optional work retry independently of the request.Ordering key, lag, retention, dead letters
Reconciliation workersWebhooks + statementsReplayable processingRuns expensive, fan-out, or side-effecting work with leases and bounded retries.Idempotency, poison work, autoscaling
Settlement viewAttempts, disputes, payoutRebuildable query stateShapes data for the dominant reads without weakening the write-side invariant.Freshness, versioning, rebuild time
Payment status APIIntent + ledger + settlementRead composition and freshness policyChooses authoritative or derived state and returns a stable client contract.Fan-out, cache policy, partial results
Payment processorAuthorize/capture/refundExternal capability, not local truthKeeps a specialized or third-party concern behind a replaceable contract.Ambiguous timeout, circuit breaking, fallback
Webhook deliverySigned at-least-once eventsConnection and delivery stateSeparates open connections and fan-out pressure from durable domain state.Reconnect, ordering, slow consumers
03

Physical design

Name the database, shard key, indexes, and guarantees.

Database + storage
PostgreSQL/distributed SQL with strong transactions owns payment intents and a double-entry ledger; queues own provider workflows/webhooks.
Partitioning / sharding
Partition by merchant or ledger account while keeping both ledger sides in one transaction domain; coordinate true cross-shard transfers.
Indexes
Unique (merchant_id, idempotency_key), provider reference, ledger (account_id, sequence), provider_event_id, and unsettled-attempt age.
Replication + consistency
Internal ledger balance and intent transitions are serializable. External settlement is asynchronous and reconciled; timeout is ambiguous.
Cache, queue + recovery
Transactional outbox/inbox, signed callbacks, append-only corrections, statement comparison, and explicit repair cases make money observable.
Capacity math
Estimate payments/sec, entries/payment, currencies, provider p99, retry volume, settlement files, and reconciliation backlog.
Alternative rejected
NoSQL event storage scales but complicates balance invariants; start with a transactional ledger and shard only with understood account locality.
04

Deep-dive candidates

Pick one risk and explain the mechanism, alternative, and cost.

Ledger boundary

Post debits and credits atomically and derive balances from entries

Mutable balance columns cannot explain money movement
Ambiguous timeout

Query the processor by stable merchant reference before creating another attempt

Retries without inquiry cause duplicate charges
Reconciliation

Compare provider statements to attempts and ledger, then queue explicit adjustments

Webhooks alone are not proof of settlement
05

Failure pressure test

Show detection, containment, recovery, and evidence.

Processor timeout

Mark attempt unknown and inquire before retry

unknown payment age
Duplicate webhook

Deduplicate provider event ID and make handler idempotent

webhook duplicate rate
Ledger posting fails

Do not report capture final; retry internal posting from durable provider result

unposted captures
Before you finish, explicitly cover
  • Functional requirements and non-goals
  • Peak traffic, storage, bandwidth, and growth
  • Entities, APIs, idempotency, and pagination
  • Source of truth and consistency promise
  • Partition key, replicas, caches, and hot spots
  • Retries, backpressure, failover, and reconciliation
  • Latency, saturation, correctness, and recovery metrics
  • Security, migration, cost, and multi-region evolution
SAY THIS WHILE YOU DRAW

A four-part talk track

  1. Scope

    “I’ll prioritize authorize, capture, refund, and query payments and never create a duplicate customer charge.”

  2. Scale

    “The design changes around exact money · asynchronous rails · zero duplicate charges · long audit retention.”

  3. Decision

    “Keep immutable ledger truth separate from mutable workflow state.”

  4. Risk

    “The first failure I want to pressure-test is: A timeout can mean the provider charged while the caller believes it failed.”

Reference details

Open these only after you can explain the diagram above without reading.

01Requirements and state lifecycle4 requirements
  • Authorize, capture, refund, and query payments
  • Never create a duplicate customer charge
  • Keep an immutable auditable balance history
  • Resolve delayed and out-of-order processor callbacks
Payment system · state lifecycle
02Data model and APIs4 entities · 4 interfaces

Core entities

PaymentIntentpayment_id, merchant_id, amount, state, versionOwner: Payment service
LedgerEntryentry_id, transaction_id, account, debit, creditOwner: Ledger
ProviderAttemptattempt_id, payment_id, provider_ref, stateOwner: Adapter
WebhookEventprovider_event_id, payload_hash, processed_atOwner: Webhook inbox

External interfaces

POST /v1/payment_intents

Create intent under merchant idempotency key

POST /v1/payment_intents/{id}/capture

Conditionally capture an authorized amount

POST /v1/refunds

Create a refund against settled payment balance

GET /v1/payment_intents/{id}

Read workflow and reconciliation state

03Deep dives and trade-offsChoose one

Ledger boundary

Post debits and credits atomically and derive balances from entries

Mutable balance columns cannot explain money movement

Ambiguous timeout

Query the processor by stable merchant reference before creating another attempt

Retries without inquiry cause duplicate charges

Reconciliation

Compare provider statements to attempts and ledger, then queue explicit adjustments

Webhooks alone are not proof of settlement
04Failures, recovery, and evidence3 scenarios

Processor timeout

Mark attempt unknown and inquire before retry

unknown payment age

Duplicate webhook

Deduplicate provider event ID and make handler idempotent

webhook duplicate rate

Ledger posting fails

Do not report capture final; retry internal posting from durable provider result

unposted captures
05What makes the answer seniorInterviewer signals
  • Say what customer-visible success means at each state
  • The ledger and payment state machine solve different problems
  • A strong answer embraces eventual external settlement without weakening internal accounting
  • Primary trade-off: Keep immutable ledger truth separate from mutable workflow state.
BEFORE THE NEXT QUESTION

Can you redraw it from memory?

  • Name the source of truth.
  • Trace the write and read paths.
  • Defend one trade-off.
  • Recover from one failure.