Design a Payment Lifecycle from Hold to Charge and Settlement
Company: OpenAI
Role: Software Engineer
Category: System Design
Difficulty: medium
Interview Round: Onsite
## Design a Payment Lifecycle from Hold to Charge and Settlement
Design a payment system whose main lifecycle is hold, charge, then settlement. A hold reserves funds, a charge captures an approved amount, and settlement moves the captured value through the external payment network and internal accounting. Make every transition retry-safe and auditable.
### Constraints & Assumptions
- Money uses integer minor units with an explicit currency.
- External processors and networks can time out, send duplicate callbacks, and report final outcomes after the client disconnects.
- A successful API response must not depend on performing two unrelated durable writes without recovery.
- The exact rules for hold expiration, partial capture, multiple capture, cancellation, and refunds must be clarified.
- Settlement is asynchronous and can differ from the earlier customer-facing charge state.
### Clarifying Questions to Ask
- Is one hold captured once in full, once partially, or through multiple charges?
- How long does a hold remain valid, and who may extend or release it?
- What user-visible state is required when the processor outcome is unknown?
- When is the merchant allowed to treat the payment as successful?
- Which currencies, processors, volumes, settlement schedules, and reconciliation files are in scope?
### Part 1 — Model the State Machine and APIs
Define resources and endpoints for creating a payment, placing a hold, charging or capturing it, releasing it, and reading status. Include idempotency and valid state transitions.
#### What This Part Should Cover
- Stable payment, hold, charge, and settlement identities.
- Amount, currency, expiry, processor references, and versioned status.
- Idempotency keys scoped to the caller and operation.
- Conditional transitions that reject invalid or duplicate actions.
```hint Model intent separately from attempts
One logical charge can survive several processor calls without turning every retry into a new financial operation.
```
### Part 2 — Execute Holds and Charges Reliably
Walk through the data flow for a hold, a later charge, timeouts, expiration, and duplicate callbacks. Explain how the system resolves an unknown processor outcome without double charging.
#### What This Part Should Cover
- Durable intent before an external call and a retry-safe work queue or outbox.
- Processor idempotency identifiers and callback deduplication.
- Pending or unknown states plus status reconciliation.
- Race handling among capture, release, and expiration.
```hint Preserve uncertainty as state
A timeout does not prove failure; record enough identity to ask the processor about the same operation instead of creating another one.
```
### Part 3 — Settle, Account, and Reconcile
Design internal ledger entries, asynchronous settlement, merchant balance updates, reconciliation, and operational visibility. Explain how corrections are represented without erasing history.
#### What This Part Should Cover
- Balanced, append-only accounting entries tied to charge and settlement IDs.
- Separation of authorized, captured, pending-settlement, and settled funds.
- Matching internal records to processor events or settlement reports.
- Exceptions, compensating entries, replay, and audit trails.
```hint Reconcile two sources of truth explicitly
The internal state machine records what the service intended and observed; processor reports confirm what the external network actually settled.
```
### What a Strong Answer Covers
- A precise lifecycle with legal transitions, idempotent APIs, and stable operation IDs.
- Safe behavior for retries, timeouts, duplicate messages, and races.
- Append-only accounting and explicit separation of charge from settlement.
- Reconciliation, observability, security, and recovery from partial failure.
### Follow-up Questions
1. What happens if a hold expires while a charge request is in flight?
2. How would you support a partial charge followed by release of the remainder?
3. Which state should a merchant webhook report when capture succeeded but settlement later failed?
4. How would you migrate one processor to another without duplicating operations?
Quick Answer: Model a payment lifecycle that moves safely from a fund hold through charge and asynchronous settlement. This system design probes idempotent transitions, unknown processor outcomes, append-only accounting, reconciliation, and auditability.