Limitless Wealth
Article

Why your ledger and your PSP disagree

Your internal record of what customers paid and your provider's record of what they settled will not match. That is normal. What matters is whether you find out from a scheduled job that expects it, or from an accountant six months later who cannot close the books.

Why they diverge

Six reasons, all structural, none of them a bug.

Timing. An authorisation is not a capture and a capture is not a settlement. Money leaves the customer, sits with the acquirer, and lands in your account days later. Any snapshot taken between those events shows a difference that is entirely correct.

Fees come out of settlement, not the transaction. You charged £100. You will receive something less than £100, and the deduction may be per-transaction, batched daily, or invoiced monthly depending on the provider. If your ledger records £100 and your bank shows £98.20, both are right and neither reconciles without modelling the fee explicitly.

Refunds settle on their own schedule, often netted against other activity rather than appearing as a discrete outbound movement.

Chargebacks arrive late. Weeks, sometimes months, after the original payment, with their own fee, and they can be reversed again if you win the dispute. A chargeback reaches back into a period you have already closed.

Currency conversion. If you charge in one currency and settle in another, the rate applied is the provider's at settlement time, not yours at transaction time. That difference is real money and it belongs somewhere in your accounts.

Partial captures and partial refunds break any assumption that one payment equals one amount.

The design that fails

Almost every system starts here: a balance column on the user, or a paid boolean on the order, updated in place as things happen.

It fails the first time something arrives out of order, and it fails silently. A chargeback lands and decrements a balance. Now the number is right but there is no record of why it changed, no way to reconstruct the balance at any past date, and no way to answer the question an accountant will eventually ask: show me every movement that produced this figure.

The deeper problem is that a mutable balance has no history. When it is wrong - and it will be - you cannot tell when it became wrong.

Double-entry, in the boring sense

The fix is a ledger, and it is much simpler than accounting terminology makes it sound. Three rules:

  • Every movement is two entries that sum to zero. A deposit credits the customer's account and debits a cash account. Money moves between places; it never appears or vanishes.
  • Entries are immutable. Nothing is ever updated or deleted. A correction is a new pair of entries, not an edit.
  • Balance is derived, never stored. A balance is the sum of entries up to a point in time. That makes any historical balance reconstructable and makes the current one impossible to silently corrupt.

Fees, chargebacks, FX differences and refunds all become ordinary entries between named accounts. Nothing needs special handling because everything is the same shape.

payment #4471  £100.00 captured

  customer:4471        +100.00
  cash:acquirer        -100.00

settlement, two days later

  cash:acquirer         +98.20
  expense:psp_fees       +1.80
  cash:bank             -100.00

If the sum of entries is not zero, you have a bug - and you find out immediately, from an invariant, rather than from a quarterly close.

Reconciliation as a scheduled job

With a ledger in place, reconciliation stops being an investigation and becomes a job that runs nightly:

  1. Pull the provider's settlement report for the period.
  2. Match each line to a ledger entry by the provider reference you stored at capture time.
  3. Post fee entries for the differences you expect - that is the fee accounting, not an exception.
  4. Anything unmatched after that is a genuine exception. Alert on it.

The important word is unmatched. A reconciliation that expects the numbers to be equal will alert constantly and be ignored within a fortnight. One that expects specific differences and flags only the unexplained ones gets read.

A reconciliation job that cries wolf is worse than none, because it teaches the team that the alert means nothing.

What to do about exceptions

Do not fix them by editing the ledger. That reintroduces exactly the mutability the design exists to prevent.

Post a correcting pair of entries against a suspense account, and keep the original. The suspense balance becomes your open-questions number - a figure someone can look at weekly and work down. It should trend to zero. When it does not, that is a signal worth having rather than a discrepancy buried inside an aggregate.

The point

None of this is exotic. It is standard practice in finance and unusual in application code, mostly because a balance column works fine right up until the first chargeback.

The cost of adding a ledger to a live system that never had one is substantially higher than building it in - you are reconstructing history from transaction logs that were never designed to support it. If you are handling money and you have a mutable balance somewhere, that is the thing to fix first.

We design payment ledgers and reconciliation, including retrofitting them into systems that started with a balance column. If yours does not currently reconcile, we can tell you why.

contact@limitlesswealth.xyz