Design a Payment Processor with Holds, Charges, and Network Batches
Company: OpenAI
Role: Software Engineer
Category: System Design
Difficulty: medium
Interview Round: Technical Screen
Design a payment processor with two separate operations. A merchant first requests a hold, which the processor forwards to an upstream payment network for approval or rejection. After a successful hold, a later charge request is grouped with other charges for the same payment network, written into a batch file, and sent on a schedule.
Explain the merchant-visible results, deduplication boundaries, scaling strategy, and reliable construction and transmission of large batches.
### Constraints & Assumptions
- Accepting a request into Kafka or another durable queue is not the same as receiving payment-network approval.
- Hold and charge are separate requests with different eligibility and response states.
- The source supplies no network-specific file format, schedule, settlement guarantee, amount policy, or retry protocol. Identify those dependencies explicitly.
- Batch construction should support parallel work by payment network and incremental preparation throughout the day.
### Clarifying Questions to Ask
- Must the hold API wait for a network decision, or may it return pending with a later status or callback?
- Which hold states and amounts permit a charge, and can a hold expire before charge processing?
- What identities do merchants and networks support for deduplication or status lookup?
- How are batch cutoffs, acknowledgments, rejected records, and retransmission handled by each network?
### Part 1 — Hold and Charge Lifecycles
Walk through request acceptance, network decisions, merchant notifications, and charge eligibility. Define what each acknowledgment means.
#### What This Part Should Cover
- Durable request identity and explicit pending, approved, rejected, or uncertain states.
- No claim of hold success merely because a queue write succeeded.
- Independent charge identity and validation against the relevant hold state.
### Part 2 — Deduplicate and Recover
Explain merchant retries, worker crashes, lost network responses, and duplicate callbacks.
#### What This Part Should Cover
- Durable deduplication at logical-operation boundaries.
- Conditional state transitions and external idempotency or reconciliation.
- Separation of a processing attempt from a new financial operation.
### Part 3 — Prepare and Send Network Batches
Design incremental charge collection, a stable batch cutoff, parallel construction, file validation, transmission, and acknowledgment handling.
#### What This Part Should Cover
- One accountable membership record per charge and a reproducible batch identity.
- Streaming or partitioned file generation with network-specific finalization.
- Transmission uncertainty and per-batch or per-record outcomes without double inclusion.
```hint Name the result returned after enqueueing
A durable queue receipt can prove that the processor accepted work. It does not contain the upstream network's hold decision unless that decision has actually arrived.
```
### What a Strong Answer Covers
- Clear hold, charge, batch, and network-outcome states.
- Deduplication and recovery at every irreversible boundary.
- Incremental batch preparation and parallelism that preserve exact charge membership and network protocol requirements.
### Follow-up Questions
- How would you recover when a network may have accepted a batch but its acknowledgment was lost?
- What happens to a charge arriving while its network's batch is being sealed?
- Why is a new filename on each retransmission not a safe deduplication strategy by itself?
Overview: Design a hold-and-charge payment processor with honest asynchronous results, durable deduplication, incremental network batches, and safe acknowledgment recovery.
Read the full OpenAI Software Engineer interview experience this question came from