Wallet balances that stay exact under retries, holds and refunds
Give every customer, merchant or sub-account its own balance. Every movement posts as a balanced double entry in integer units, and a retry with the same reference can never move the money twice.
Where this usually goes wrong
Floating-point balances drift
A wallet that adds 0.1 and 0.2 in floating point will, sooner or later, disagree with the bank. Small errors compound across millions of postings.
Retries double-post
A mobile client times out and resubmits. Without a stable idempotency key enforced by the ledger, the same top-up or transfer lands twice.
Edits erase history
When support fixes a balance in place, nobody can explain the number later. Auditors and regulators expect the original entry and its correction.
Primitives in the open-source core, not patterns you rebuild
Integer units, explicit precision
precise_amount 1250 at precision 100 is 12.50. Inputs the ledger can't represent exactly, including positive amounts that round to zero, are rejected before posting.
One reference per operation
A reused reference is rejected with TXN_DUPLICATE_REFERENCE and the balances don't change. After a timeout, recover the original with GET /transactions/reference/:reference.
Holds for pending spend
inflight: true reserves funds and reduces the available balance. Commit all or part of the hold, or void the remainder.
Corrections as new entries
A refund is a linked reversal for the original's exact units. Postings are never edited, so the history keeps both sides of every correction.
Bounded overdrafts
Overdrafts are explicit per transaction. Set overdraft_limit to cap how far a balance may go into a debit position.
History and identities
Take balance snapshots, read a balance as it stood at a point in time, and link people or organisations to their balances.
A 12.50 USD wallet transfer, and its retry
{ "source": "bln_e0f81b15-bd0a-43c5-9e84-7fd4394192e8", "destination": "bln_df56a248-7d7e-4c0c-8fbf-a5215c87b603", "currency": "USD", "precise_amount": 1250, "precision": 100, "reference": "order-1042", "description": "Order 1042", "skip_queue": true, "allow_overdraft": true, "overdraft_limit": 12.5}{ "rate": 0, "precise_amount": 1250, "amount": 12.5, "amount_string": "12.5", "precision": 100, "overdraft_limit": 12.5, "transaction_id": "txn_c493a7e3-ac39-4456-90c3-ac43f00c5e0d", "parent_transaction": "", "source": "bln_e0f81b15-bd0a-43c5-9e84-7fd4394192e8", "destination": "bln_df56a248-7d7e-4c0c-8fbf-a5215c87b603", "reference": "order-1042", "currency": "USD", "description": "Order 1042", "status": "APPLIED", "hash": "9b7d7ad924e2e626055e3b33edcf194142e3fcd562de1807dd738d9afd7c1f87", "allow_overdraft": true, "inflight": false, "skip_queue": true, "atomic": false, "created_at": "2026-10-10T05:54:45.691597464Z", "effective_date": "2026-10-10T05:54:45.691597464Z", "scheduled_for": "0001-01-01T00:00:00Z", "inflight_expiry_date": "0001-01-01T00:00:00Z", "inflight_commit_date": "0001-01-01T00:00:00Z", "meta_data": { "allow_overdraft": true }}{ "error": "reference has already been used", "error_detail": { "code": "TXN_DUPLICATE_REFERENCE", "message": "reference has already been used" }}Put a provable ledger under your money movement
Start with the open-source core, or let the LedgerForge team run it for you on dedicated infrastructure.