Katkat

Design a Reliable Bank Payment System

J.P. MorganSoftware Engineer · Onsite

Last updated

Design a reliable bank payment system that remains correct across retries, crashes, duplicate requests, and ambiguous external-rail timeouts. Define idempotent APIs, a durable state machine and ledger, transactional handoff, safe reconciliation, invariant monitoring, auditability, and operator remediation.

Design a Reliable Bank Payment System

Design a backend that accepts a customer's request to transfer money, tracks the payment through processing, and exposes its current status. The most important requirement is reliability: retries, crashes, duplicate requests, and uncertain responses from an external banking rail must not create an untracked or duplicated transfer.

Organize the design around requirements, API flow, data model, failure handling, and operations. Do not assume a particular transaction volume; explain which capacity facts would change your choices.

Constraints & Assumptions

  • A payment has a durable identity and an explicit state machine.
  • Clients and internal workers may retry requests.
  • An external processor can time out after accepting a request, leaving the local result uncertain.
  • Money values use an exact representation and include currency.
  • A user must be able to query a payment after the initial request returns.

Clarifying Questions to Ask

  • Is this an internal ledger transfer, an external bank transfer, or both?
  • Which states and cancellation rules are visible to users?
  • What consistency and completion-time expectations apply?
  • Who is authoritative for final settlement, and how are disputes or reversals handled?
  • What compliance, audit, retention, and regional constraints apply?

Solving Hints

  • Separate accepting an intent from completing an external side effect.
  • Define retry behavior at every boundary, including the ambiguous timeout case.
  • Treat reconciliation as part of the normal design, not an emergency-only tool.

Follow-up questions

  • What should happen when the processor times out but may already have sent the money?
  • How would you prevent two concurrent cancellation and completion requests from both succeeding?
  • Which invariants would you monitor continuously?
  • How would you migrate or shard the payment table without losing idempotency?