# Design a Payment System and Ledger — High-Level & Low-Level Design Interview Problems

Source: https://www.skillbyai.com/en/design-interviews/payment-ledger

> Double-entry, idempotency, reconciliation.

## Correctness first

A payment system must never lose or duplicate money. Components: a **payment service** that accepts requests with an **idempotency key**, a **payment executor** that calls external providers (card networks, banks via a payment service provider), a **ledger**, and a **reconciliation** job. The ledger uses **double-entry bookkeeping**: every transaction writes at least two entries whose debits and credits sum to zero, so balances can be derived and audited. Entries are **append-only**; corrections are new reversing entries, never edits. Store amounts as integers in minor units (or a decimal type) with a currency, never floating point. Reconciliation compares the internal ledger against provider settlement files and flags mismatches for investigation.

## Double-entry data model

Illustrative schema and a transfer.

```text
accounts(id, owner, currency, type)            -- e.g. user wallet, merchant, fees
transactions(id, idempotency_key UNIQUE, status, created_at)
entries(id, transaction_id, account_id, amount_minor, direction DEBIT|CREDIT)

Transfer 50.00 from customer to merchant with a 1.00 fee:
  txn T1 (idempotency_key = "pay-8842")
    DEBIT  customer_wallet   5000
    CREDIT merchant_account  4900
    CREDIT platform_fees      100
  sum(debits) = sum(credits) = 5000   -- checked in the same DB transaction

Balance(account) = sum(credits) - sum(debits)   (or a maintained balance row
                   updated in the same transaction, for liability-style accounts)
Retry with same key -> UNIQUE constraint hit -> return the original result
```

## Expect unknown outcomes

Calls to a provider can time out with the result unknown. Mark the payment as pending, retry with the same idempotency key, and let webhooks and reconciliation settle the final state.

**Quiz:** How is a mistaken ledger entry corrected in a double-entry ledger?

- [x] By appending a reversing entry, keeping history intact
- [ ] By editing the original amount
- [ ] By deleting the transaction row
- [ ] By changing the account balance directly

*Answer:* By appending a reversing entry, keeping history intact. Ledgers are append-only for auditability.
