Ledger infrastructure
Hostra keeps a double-entry ledger as the source of truth for money movement. Every transaction is a balanced set of debits and credits, entries are immutable once written, and balances are derived from those entries rather than stored and edited in place.
Why double-entry
A single-column balance can be wrong without anyone noticing: an update is applied twice, a refund is written but the fee is not, and the number in the database no longer explains itself. Double-entry makes an incorrect state structurally invalid — a transaction that does not balance is not committed. It also means the answer to "why is this balance what it is" is always the list of entries that produced it.
The model
- Account
- A named position in the chart of accounts — merchant balance, provider clearing, fee income, network cost.
- Entry
- A single debit or credit against one account, carrying amount, currency and minor-unit precision.
- Transaction
- A set of entries that must balance to zero across debits and credits before it is committed.
- Posting rules
- Deterministic mapping from a settlement event to the entries it produces, so the same event always posts the same way.
- Balance
- A derived value computed from entries, not a mutable counter that can drift from history.
- Audit record
- A hash-chained record of the state change, verifiable through the audit proof endpoint.
Properties
- Balanced: debits equal credits inside every committed transaction.
- Immutable: entries are appended, never edited. A correction is a new, compensating transaction.
- Derived balances: a balance is a function of entries, so history and state can never disagree.
- Minor units: amounts are held in integer minor units to avoid floating-point rounding drift.
- Deterministic: the same settlement event replays to the same postings, which is what makes retries safe.
- Auditable: each state change extends a tamper-evident hash-chain that can be verified independently.
Relationship to settlement
The ledger does not call providers and the settlement engine does not invent accounting. The engine owns the lifecycle of an intent — pending, in_flight, succeeded, failed or reversed — and each transition emits the postings defined for it. Because the engine commits exactly once, the ledger never sees a duplicated posting for a single execution; because postings are deterministic, a replayed event cannot produce a different accounting result.
Reconciliation
Reconciliation compares three sources: what the ledger says happened, what the settlement engine recorded as the terminal state of the intent, and what the provider or network reports. Because ledger entries are immutable and hash-chained, a discrepancy is always attributable to a specific transaction rather than to an unexplained balance difference. Discrepancies are resolved by posting a compensating transaction, which keeps the original history intact.