Katkat

Design a Payment Lifecycle from Hold to Charge and Settlement

OpenAISoftware Engineer · Onsite

Last updated

This problem tests the design of a distributed, idempotent payment processing system that ensures data consistency and financial integrity across asynchronous state transitions.

Problem Statement

Design a payment orchestration service that manages the lifecycle of a transaction from PENDING_HOLD to CHARGED and finally SETTLED. The system must interact with external payment gateways that are unreliable and often exhibit high latency.

Functional Requirements

  1. Lifecycle Management: Support transitions: CREATED -> HOLD -> CHARGED -> SETTLED (or FAILED at any point).
  2. Idempotency: Requests to charge or settle must be idempotent to prevent double-charging or inconsistent states when retrying after a gateway timeout.
  3. Accounting: Ensure every state change is recorded in an immutable ledger for audit purposes.
  4. Asynchrony: Handle external gateway responses asynchronously via webhooks or polling.

Constraints & Scale

  • The system should handle 5,000 transactions per second (TPS) during peak hours.
  • The system must prioritize financial accuracy over low-latency consistency (eventual consistency for reporting is acceptable, but transaction states must be strictly consistent).
  • External gateways may return "In Progress" or "Unknown" statuses.

Deliverables

  • Define the API endpoints for the client service to interact with your system.
  • Propose a database schema for the Transactions and Ledger tables.
  • Describe how you handle the "Unknown" state returned by a third-party processor.
  • Sketch a high-level architecture, including how you ensure the atomicity of updating the transaction state and recording the ledger entry.

Hints

Hint 1

Use a state machine pattern to enforce valid transitions and ensure the current state is checked before any update.

Hint 2

Implement the 'Outbox Pattern' to ensure that state changes and ledger updates happen atomically or at least guarantee eventual consistency.

Hint 3

For the 'Unknown' gateway outcome, consider an inquiry mechanism (polling) paired with a TTL-based retry queue to reconcile the state.

Follow-up questions

  • How would you handle a scenario where a user disputes a charge after it has been settled?
  • What specific mechanisms would you use to reconcile your internal database against the bank’s daily settlement report (e.g., CSV files)?
  • How would you scale the system if you needed to support multiple payment processors (Stripe, Braintree, etc.) with different API schemas?