Katkat

Design a payment system with holds and batching

OpenAISoftware Engineer · Technical Screen

Last updated

This question tests the ability to design a high-consistency payment processing system that handles asynchronous state transitions, authorization holds, and batch settlement workflows.

Design a Payment System with Holds and Batching

Design a payment processing service that supports two distinct flows: Immediate Charges and Authorization Holds with Delayed Settlement.

Your system must support a credit-based API where a merchant can initiate a hold on a user's funds, which is then either captured (settled) in a batch at the end of the day or released.

Requirements

  • Functional:
    • charge(user_id, amount): Perform an immediate synchronous charge.
    • authorize_hold(user_id, amount): Reserve funds without capturing them immediately.
    • capture_hold(hold_id): Finalize a specific held transaction.
    • release_hold(hold_id): Void a held transaction.
  • Non-Functional:
    • Idempotency: Ensure that retried requests do not result in double-charging or duplicate holds.
    • Consistency: The system must accurately reflect available balance vs. held balance.
    • Reliability: Payments must be auditable; handle system failures during the capture or settlement process.
    • Scale: Support 1,000 requests per second and batch processing for millions of records daily.

Your Deliverables

  1. Data Model: Define the database schema for transactions, holds, and status tracking.
  2. Architecture: Describe the services and communication patterns (synchronous vs. asynchronous).
  3. Batch Workflow: Explain how the system handles the batch settlement process to ensure no transaction is missed or settled twice.
  4. Failure Handling: Describe how you handle the scenario where a network timeout occurs during an external payment gateway call.

Hints

Hint 1

Use a state machine for the hold lifecycle (e.g., PENDING, CAPTURED, VOIDED, EXPIRED) to ensure atomic state transitions.

Hint 2

Implement an idempotency key at the API level and store it in the database to prevent duplicate side effects from retried requests.

Hint 3

For batch settlement, use an idempotent 'status' update strategy or a message queue to process transactions in bulk without blocking the main request path.

Follow-up questions

  • How would you handle a situation where a user's balance is sufficient during the hold, but they withdraw funds before you attempt to capture the payment?
  • If the batch settlement job fails midway through, how do you ensure the system remains in a consistent state and resumes correctly?
  • How would you implement a 'reconciliation' service to detect discrepancies between your internal ledger and the actual bank/gateway reports?