10 min read

How Ledger Balances Work

A ledger balance sheet showing posted, credit, debit, and inflight balances.
On this page

A ledger records how value changes across accounts. A deposit or payment is a transaction, and each recorded change to an account is a ledger entry. Together, those entries form the history you can use to explain a balance.

When you build a wallet, the balance gives your app an amount to show Alice, while the ledger entries explain how it got there. If her wallet shows $7 and she questions it, those entries let you trace and rebuild the balance; a field that only stores the latest amount cannot.

In this article, we'll explain how ledger balances work by connecting the amount your app reads to the transaction records behind it. You'll see when a transaction changes that amount, why one account can have different balances, and how to check the result against the ledger.

What a balance is

A balance is the amount a ledger reports for an account at a particular moment. The ledger can record a transaction while it is still pending, but having a record does not mean its amount has been added to the account. A balance based on completed transactions counts the change only when the transaction completes.

Imagine Alice's USD wallet starts at $0. She makes a $10 deposit, and the ledger records it as pending. Her balance from completed transactions stays at $0. If the deposit succeeds, the ledger credits her wallet and that balance becomes $10. If it fails, the record of the attempt remains, but her balance stays at $0.

After the successful deposit, Alice starts a $3 payment. The ledger can record the payment while it is pending, but her balance from completed transactions remains $10. When the payment completes, it falls to $7.

The interaction below follows that deposit and payment.

Alice's balance rises by $10 and falls by $3, but those changes do not tell us where the money came from or went. To follow each movement, we need to look at the accounts on the other side.

Money movement

A money movement changes the balances of the accounts it connects. Alice's $10 deposit moves value from a funding account into her wallet; her $3 payment moves it from her wallet to a merchant account. Each account has its own record of the change, even if the app only shows Alice's balance.

Not every balance belongs to a customer. Funding, settlement, fee, and revenue accounts also give money movements a defined source or destination.

Now Alice has $7 and James has $0. If she sends him $1, her wallet falls to $6 and his rises to $1. One transfer changes two balances, but together the wallets still hold $7.

The table shows two account entries for each transfer. Both entries share a transaction ID: txn_001 links Alice's $1 decrease to James's $1 increase, while the next transfer gets a new ID. You can use that ID to retrieve both sides and check that neither is missing.

Here, Alice's outgoing entry is called a debit and James's incoming entry is called a credit. That describes their effect on these customer wallets, not a universal rule that debits subtract and credits add. In accounting, the effect depends on the type of account: a debit increases an asset account but decreases a liability account; a credit does the reverse.

A balance needs history

Before Alice sent James $1, her wallet held $7. That balance could have come from different transaction histories. Each of the three below starts at $0 and ends at $7, but the deposits and payments behind it differ.

Switch between the histories below. Each table shows how the balance changes after every entry.

History A shows the $3 payment that brought Alice's balance from $10 to $7. If that payment is refunded, record a new transaction that credits her wallet $3 and refers to the original payment ID. Her balance returns to $10, but the history still shows the deposit, payment, and refund. That $10 tells a different story from a $10 balance where the payment never happened.

Running and aggregated balances

When Alice opens her wallet, your app needs to show her current balance. Summing every deposit and payment each time would take more work as her history grows. A running balance keeps the latest total ready to read and updates it when a completed entry changes her wallet. In History A, it stores $10 after the deposit and $7 after the payment, before any refund.

If you do not need to keep that total ready for every read, you can calculate an aggregated balance from completed entries when you request it. For Alice, it adds the $10 deposit and subtracts the $3 payment to return $7. You can also use that calculation to check a stored running balance. It avoids updating a separate total with each entry, but each read has more history to process as entries accumulate.

These are not two different balances. Both methods use the same completed entries and should return $7. If the stored running balance says $8 while those entries add up to $7, the stored value no longer agrees with its history.

To calculate Alice’s posted balance at a given time, include only entries for her USD wallet that were posted by then. Treat increases as positive amounts and decreases as negative amounts:

posted_balance
posted_balance(account, currency, as_of) =
sum(entry.amount for entry in entries
if entry.account == account
and entry.currency == currency
and entry.status == "posted"
and entry.posted_at <= as_of)

Both methods must apply that same rule. If the stored balance must reflect a completed entry immediately, commit the entry and total together. An asynchronously updated total may lag behind the entries and must remain checkable against them.

Posted and available balances

A ledger can report more than one balance for the same account. The posted balance reflects completed entries. The available balance shows how much Alice can spend after accounting for holds on unfinished payments. A hold can reduce Alice's available balance without changing her posted balance.

Posted balance

The posted balance is the amount produced by completed entries. You use it when an account statement or reconciliation check needs to match the ledger's completed records. Say Alice starts a $10 bank top-up. The app can show it as pending, but her posted balance remains $0. Once the top-up completes and the ledger records its $10 credit, her posted balance becomes $10.

Available balance

The available balance is the amount Alice can spend under the product's rules right now. Say she has $10 in her wallet and taps her wallet-linked card for a $4 coffee. The cafe's authorization reserves $4 before the payment posts, so her posted balance stays $10 while her available balance falls to $6. With only $6 available, an $8 purchase should be declined unless your product allows overdrafts, even though the posted balance still says $10.

Alice’s posted balance is $10, but $4 of it is reserved for the cafe payment. The hold is not another $4 in her wallet; it leaves $6 available to spend. What happens to the hold depends on how the payment proceeds.

Payments can be recorded before they are complete. A payment may reserve funds while it waits for confirmation, then complete or be canceled; money returned afterward is recorded as a refund. This sequence of recorded states and outcomes is the payment lifecycle. You need to know the payment's state to tell whether funds are reserved, spent, released, or returned.

Alice's cafe purchase shows one version of that process. Authorization reserves $4, leaving $10 posted and $6 available. Capture confirms that collection should proceed while the hold remains in place. When the completed $4 debit posts, the hold clears and Alice has $6 posted and $6 available. If the payment is canceled before capture, releasing the hold restores $10 available. If it is refunded after posting, a new $4 credit returns Alice to $10 without removing the original payment.

Historical balances

A historical balance tells you what an account's balance was at a chosen time in the past. You need that earlier amount when producing a statement or checking what the ledger showed before a later transaction. Alice has $6 after her $4 cafe payment, but that does not mean she had $6 all day.

Her wallet was $0 at 08:00. A completed $10 deposit at 09:00 brought it to $10, and the $4 payment recorded at 14:00 reduced it to $6. At noon, the deposit had posted but the payment had not, so Alice’s posted balance was $10. By 15:00, it was $6.

The $0 at 08:00 is a snapshot: a saved balance you can start from instead of replaying the account's entire history. Select a time to see which later entries count toward Alice's balance.

If there is no snapshot, calculate the historical balance by applying every eligible entry from the account’s beginning through the requested time. A snapshot saves you from replaying that entire history. You must also choose a timestamp. By posting time, Alice’s noon balance is $10 because her payment was not recorded until 14:00. If the payment is later assigned an effective time of 11:00, a report recalculated by effective time shows $6 for noon. Make clear which timestamp your historical balance uses.

Rebuilding a balance

A running balance stores the latest total so your app does not have to add up every entry on each read. If an update to that total is missed, the stored balance can disagree with the transaction history. Rebuilding a balance means recalculating it from trusted entries and correcting the stored total. You need to do this when a processing failure or bug leaves the stored balance out of sync with the ledger.

Alice's posted entries are a $10 deposit and a $4 payment, so her balance should be $6. Suppose the stored balance says $8. Recalculate from her entries to find the $2 difference, then rebuild the stored balance to $6. No new payment occurred, so adding a $2 transaction would create a false history rather than fix the missed update.

Compare the stored balance and the entries at the same committed ledger version, using the same rule for which entries count. Otherwise, a payment being recorded during the check can look like a mismatch. If the difference is real, investigate why the stored update was missed. Rebuilding corrects the stored total; it does not rewrite Alice's deposit or payment.

Balance monitoring

Rebuilding checks whether a balance agrees with its entries. Monitoring serves a different purpose: it watches a specified balance field for a condition that matters to the product. The rule needs an account, a field, a comparison, and a threshold. A threshold crossing can then trigger an alert without changing the ledger.

Alice has enabled a low-balance alert for her posted balance, with a $5 threshold. Her balance is $6. When another $2 payment posts, it falls to $4 and triggers the alert. If she monitored her available balance instead, a $2 hold could trigger the alert before the payment completes. The balance field you monitor determines when the alert fires.

Send the alert once when Alice’s monitored balance falls from $6 to $4. Do not send it again each time the app reads the same $4 balance. If processing retries, use the triggering event or balance version to prevent duplicate alerts. The alert signals a threshold crossing; it does not verify that the balance is correct. Checking the ledger records serves that separate purpose.

Conclusion

When your app displays a balance or uses it to approve a payment, you should know which account and currency it belongs to, which entries count, and when the answer applies. A stored total makesWhen your app displays a balance or uses it to approve a payment, you should know which account and currency it belongs to, which entries count, and what point in time it represents. A stored total makes the balance quick to read, but the ledger records must still let you recreate and explain it when a payment decision, customer question, or reconciliation check depends on it. that answer quick to read, but the ledger records must still let you recreate and explain it when a payment decision, customer question, or reconciliation check depends on it.

If you're building a wallet or payment product, explore Blnk Core.