- Fintech
- Custom SaaS Development
- Discovery Workshop
- DevOps
When two systems disagree about a balance
A payments business grows until the month end reconciliation between its own records, its processor and its bank stops fitting into a spreadsheet. A double entry ledger with scheduled reconciliation turns that from a monthly investigation into an exception queue.
Representative engagement. This describes a pattern we build rather than one named client: the situation that produces it, how we approach it, and the range of outcomes that kind of work lands in. Figures are stated as ranges or targets, never as a measured result for a specific customer. Our named client work is on the work index.
- Industry
- Fintech
- automated reconciliation instead of a month end investigation
- Daily
- any historical balance reconstructable from the ledger
- Point in time
The problem
Balances live in three places and agree most of the time. The trouble is the rest of the time: a webhook arrives twice, a refund lands in a different period from its charge, a payout is netted differently from how it was recorded. Each one is small and each one takes an afternoon to explain. Underneath is a design problem rather than a diligence problem. Records that can be updated in place cannot be reconstructed, so nobody can answer what a balance was on a Tuesday three months ago. That question comes up during audits, disputes and diligence, which are exactly the moments when not knowing is expensive. Retrofitting a ledger is the least popular migration in software, because it runs on live money. Which is precisely why it gets deferred until it is unavoidable.
What we built
An append only double entry ledger as the system of record, with every movement expressed as balanced entries and nothing ever edited in place. A correction is a new entry, which means history stays readable. Every write path is made idempotent against the provider's own identifiers, so a webhook delivered twice produces one entry rather than two. Reconciliation runs on a schedule against processor and bank statements, and anything that does not match becomes a case with an owner instead of a discrepancy somebody finds later. Migration runs in parallel. The ledger is built alongside the existing records and reconciled against them daily until the two agree without intervention, and only then does anything depend on it.
What changed
Month end stops being an investigation. Most breaks are caught the day they happen, by the job rather than by a person, and the ones that need judgement arrive as a short queue rather than a spreadsheet. The durable part is being able to reconstruct any balance at any past moment. It is invisible right up until an auditor, a disputed transaction or a data room asks for it, at which point it is the only thing that matters.
Built with
- TypeScript
- Go
- PostgreSQL
- Stripe
- Temporal