All work

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 - Distributed payments ledger

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.