BackendForFintech
Wallet Systems

Designing a Double-Entry Wallet Ledger for Fintech Startups

14 min readWallet Systems2024-01-15

Every payments or lending startup needs a ledger. A simple balance column is not enough: it invites race conditions, makes audit trails impossible, and breaks under reconciliation. This note covers the foundational double-entry model and how to implement it.

Debit/credit model

Every transaction is recorded as paired debits and credits. The sum of debits equals the sum of credits for each transaction. Balances are derived by aggregating the journal; they are not updated in place.

Ledger structure
Transaction Journalappend-only • immutabletx_1 W-A DR 100 USDtx_1 W-B CR 100 USDtx_2 W-B DR 50 USDtx_2 W-C CR 50 USD...id • account • type • amount • currencyaggregateBalance Snapshotsderived from journalaccount_idcurrencybalanceW-AUSD150.00W-BUSD50.00W-CUSD50.00CR = credit (inflow), DR = debit (outflow)Sum of DR = Sum of CR per transactionDouble-EntryDR (Debit)asset increaseCR (Credit)asset decreaseEvery tx balances
sql
-- Journal entries (immutable)
INSERT INTO journal (tx_id, account_id, type, amount_cents, currency)
VALUES
  ('tx_1', 'wallet_A', 'DR', 10000, 'USD'),
  ('tx_1', 'wallet_B', 'CR', 10000, 'USD');

Balance calculation strategy

Balance = sum(credits) − sum(debits) per account and currency. Compute from the journal or maintain materialized views/caches that are updated only by appending to the journal and recomputing. Never update balance rows in place.

Preventing negative balances

Enforce at transaction time: before appending a debit, check that available balance (balance − holds) is sufficient. Use a single serializable transaction or optimistic locking so concurrent debits cannot overdraw.

Reconciliation principles

The journal is the source of truth. External statements (banks, gateways) are matched to journal entries by reference id, amount, and date. Mismatches go to an exception queue. Reconciliation runs in batches with clear cut-off times.

Why not a simple balance column

A single balance column forces in-place updates. Under concurrency you get lost updates or race conditions. There is no audit trail. You cannot reconcile to external records. Double-entry gives you consistency, auditability, and a path to scale.

Book Architecture Strategy Call

Schedule a call →