Ledgers and Reconciliation: The Real Skeleton of a Payment System

Part V · Players and Risks (Chapters 20–25) Builds on: Chapter 1 (the ledger, atomicity), Chapter 7 (authorization separated from capture), Chapter 22 (Synapse's ledger mismatch), Chapter 24 (compliance actions land on the books) New concepts in this chapter: double-entry bookkeeping, journal entries, reconciliation, breaks, idempotency, state machines, asynchronous callbacks

Every mechanism the earlier chapters covered ends up as the handful of tables and rules in this one.


1. The Questions the Previous Chapter Left Open

The previous chapter ended by asking: sanctions screening intercepts a payment — whose money is it counted as, right now? A transaction is returned — what happens to the original record? A user's balance — what proves it is that number?

The Synapse case in neobank anatomy already supplied the answer's dark side — when the ledger breaks, the money might as well not exist.

This chapter is about keeping the ledger from breaking.


2. Double-entry bookkeeping isn't an accounting preference — it's mandatory

Go back to the table in the nature of payment. One transfer: Dean down 100, Alice up 100, and both lines must change together.

Double-entry bookkeeping — every movement of money is recorded as a debit and a credit at once, and the two sides must be equal — turns that requirement into a constraint on the data structure.

The journal entry (the smallest unit of a bookkeeping action) for a user topping up $100:

Account Debit Credit
Cash at bank (our money at the bank) 100
Payable to user (what we owe this user) 100
Total 100 100

The key: debits must equal credits, and the system enforces it.

What that buys you: "money appears from nowhere" and "money vanishes into nowhere" become impossible at the level of the data structure. Any balance anomaly must trace back to some unbalanced entry — and an unbalanced entry is one the system refuses to write at all.

Compare the approach that skips double-entry.

The most common version is a balance column on the users table: each user's database row stores one balance number; a transfer subtracts 100 from one row, adds 100 to another, done.

The problem is not that it doesn't run — it runs, and plenty of systems started exactly this way. The problem is that it stores only the result, never the process:

Approach What the books store What an error looks like Can it be caught?
Balance column on the users table One number — the balance The balance becomes a wrong number Barely: there is no reference to check against
Double-entry A debit-credit entry for every change; balances are computed from the entries The entry refuses to write, or the first totaling shows the two sides unequal Immediately

This is why a payment system must use double-entry. The balance-column approach runs fine as a feature — and when something goes wrong, it cannot vouch for itself.


3. Reconciliation: Check Against the Outside, Not Yourself

An internally consistent ledger is only step one. Step two is comparing it, line by line, against your external counterparties' records — reconciliation.

There are at least three counterparties to reconcile against:

Reconcile against What you compare Common causes of differences
The partner bank's statement Our booked balance vs. the bank's actual balance Money in flight; fees not yet booked
The card network's clearing files Transactions we recorded vs. transactions the network cleared Authorizations never captured; refund timing gaps (the card transaction lifecycle)
Each payment channel's statement Every transaction's amount, status, and fees Status updates lagging on the channel side

A line that doesn't match is called a break.

The only correct posture toward breaks: every one gets investigated and driven to zero. None stays hanging.

The reason is the second of the three lessons in neobank anatomysmall differences, left to accumulate, become an unrecoverable black hole under pressure. When Synapse blew up, the problem was not $85 million going missing on a single day. It was years of unreconciled differences piling up until nobody could take them apart.

A working standard:

Reconcile daily, and drive breaks to zero the same day. Any break that can't be resolved that day gets a named owner and an expected resolution date, with the amount parked in its own account, visibly.


4. Three System Properties You Must Master

These three are the biggest difference between a payment system and an ordinary business system.

Idempotency

Definition: the same request, sent any number of times, takes effect exactly once.

Why it's non-negotiable: networks time out. A client fires a payment and the wait for a response times out — did the payment succeed or not? The client cannot know. All it can do is retry.

With idempotency Without
The retry is recognized as the same payment and returns the first result The retry becomes a second payment, and the user is charged twice

How it's built: every request carries a unique identifier generated by the sender (the idempotency key); the server records the keys it has processed and answers duplicates with the original result.

A payment API without idempotency is a double charge waiting to happen.

The state machine

Definition: a transaction's status may only move along paths defined in advance.

Take the card-transaction statuses from the card transaction lifecycle:

Current status May move to May not
Authorized Captured, voided, expired Refunded (nothing was captured, so there is nothing to refund)
Captured Settled, refunded Voided (the void window has closed)
Refunded Terminal Refunded again

What happens without one: illegal states — "refunded, then charged again," "voided, then successfully captured." In production these are brutal to debug, because the data itself is self-contradictory.

Asynchronous callbacks

Definition: the result of an operation arrives because the other side actively notifies you (a callback), not because you waited synchronously for a return.

The card transaction lifecycle showed the three phases of a card transaction spanning one to two days. The batch-net rails in push and pull span one to three. No synchronous interface waits that long.

Three requirements come bundled:

Requirement Why
Callbacks must be retryable Your service may be down at exactly the wrong moment
Callback handling must be idempotent Retries mean the same callback arrives more than once
There must be an active-query fallback The callback may never come; you cannot depend on it alone

The last one gets skipped most often. Callbacks without active querying means that when the other side's system fails, your transactions hang in an intermediate state forever.


5. Tying Together Everything That Came Before

The value of this chapter is that it is where everything earlier lands. Check:

Mechanism covered earlier How it lands in the ledger
Authorization is not a charge (the card transaction lifecycle) An authorization is logged for reference only, no formal journal entry; the entry is written at capture
ACH can be returned (push and pull) Revenue cannot be recognized as final until the return window closes
Chargebacks (the card transaction lifecycle) A reversing entry plus a dispute-fee entry
Rolling reserve (the five risks) Parked in its own account; transferred out only when released at maturity
Prefunding (the four cost sources) A separate account per country pool, so liquidity can be watched
Sanctions freezes (the compliance skeleton) Funds move to a frozen account, excluded from the user's available balance
The FBO account (neobank anatomy) The internal ledger must reconstruct, line by line, what belongs to each user

These seven rows are the minimum checklist for ledger design. The Synapse disaster in neobank anatomy failed on exactly the last row.


6. The Question This Chapter Leaves Open

Part V ends here, and with it the skeleton of the whole old world is complete:

Now we can ask the question that has hung in the air since the end of the Wise model. Verbatim:

Is there an asset that can move instantly between any two parties on earth, with no pile of money parked in every country?

Part VI answers it head on. But before the answer, the asset has to go back into the table from the hierarchy of moneywhose liability is it?

The next chapter starts from that question.


7. Self-check questions

  1. Why is "a balance column on the users table, incremented and decremented directly on each transfer" unacceptable in a payment system?
  2. Your service receives a payment-success callback, and the database write fails while handling it. The other side will retry. What property does your system need for nothing to go wrong?
  3. $1,000 arrives over ACH. When can it be recognized as final revenue?

8. Answers

Answer for yourself before reading on.

  1. Because it cannot vouch for itself. The approach stores one number — the balance — and nothing about how it became that number. When the balance is written as a wrong value, the system has no reference for noticing: you don't know what the correct value should have been, or when the error entered, or through which operation. Double-entry requires every change to book a debit and a credit of equal amount; any imbalance is rejected at write time, and any historical value can be recomputed from the entry stream. One stores only the result; the other stores the whole process that produced the result — and that is what makes a ledger auditable and reconstructible.

  2. Idempotency. The callback handler must key on a unique identifier (usually the counterparty's transaction number or callback event ID), recognize a duplicate as the same event, and return success rather than book the entry a second time. It also needs the active-query fallback — if the other side runs out of retries before you've processed successfully, you must be able to go ask for the transaction's final status yourself. Idempotency without active querying can still leave you stuck forever.

  3. Strictly: when the return window closes. The unauthorized-return window on consumer accounts (R10) runs up to 60 days, so the most conservative answer is after 60 days. In practice it's tiered by risk: low-risk users and small amounts are recognized after a few business days, with a bad-debt provision set aside; high-risk ones wait longer. The point is that on the day it lands, the money is not final revenue — and arranging your cash as if it were is the single most common way products like this blow up.


Previous: Chapter 24 · The Compliance Skeleton: Licenses, Identity, and Monitoring Next: Chapter 26 · What Stablecoins Are: Back to the Hierarchy-of-Money Table