Distributed payments ledger
Ledgerline
A double-entry ledger that reconciles millions of daily transfers without drift. Event-sourced core, idempotent writes, and a replayable audit trail.
Cut reconciliation lag from hours to near real time.
- GoPostgreSQLKafka
Ledgerline is the money-movement core behind a payments platform. It has one job that cannot be negotiated: every transfer must balance, and the books must always agree with reality.
The problem
The previous system reconciled in nightly batches. When a mismatch appeared, the offending transfer could be twelve hours old, buried under a day of activity. Debugging money at that distance is slow and expensive.
The design
I rebuilt the core as an event-sourced, double-entry ledger. Every movement is two entries that sum to zero, appended as immutable events.
type Entry struct {
AccountID string
Amount int64 // minor units, signed
}
func Post(txID string, entries []Entry) error {
var sum int64
for _, e := range entries {
sum += e.Amount
}
if sum != 0 {
return ErrUnbalanced // a transaction that does not balance never lands
}
return store.AppendIdempotent(txID, entries)
}- Idempotent writes keyed on the transaction id, so retries never double-post.
- Append-only events give a full audit trail for free.
- Projections rebuild balances by replaying events, so reconciliation is continuous rather than nightly.
The outcome
Reconciliation moved from a nightly batch to a streaming projection. Mismatches now surface within seconds of the transfer that caused them, while the context is still fresh.