CorebanqCorebanq Developer Docs
Ledgers

Description

Ledgers & Balance Management

The CoreBanq Ledger System is a high-performance, double-entry accounting engine. It serves as the "source of truth" for all financial positions, providing real-time balance tracking, hierarchical aggregation, and administrative holds.

Purpose and use

Ledgers record the bank's financial truth: customer money, bank money, fees, suspense, settlement, holds, and control balances. Every balance-affecting operation should be explainable from ledger entries and their roll-up into the chart of accounts.

Who uses this. Finance controllers, operations staff, reconciliation teams, auditors, treasury users, and support teams use ledgers to answer balance, posting, safeguarding, and audit questions. Regulatory reporting teams use the same subledger structure to prepare safeguarding figures, and product teams use it to decide where a new money flow should be booked.

How it works. Customer-facing accounts map to subledgers. Subledgers roll into control ledgers. Ledger entries debit and credit those ledgers, while holds adjust available balance without changing posted balance until settlement occurs.

What users do. Users review ledger hierarchy, inspect balances, place or release holds, post journal entries through controlled flows, and trace a transfer or fee back to its accounting entries.

Outcomes and side effects. Ledger postings update posted and local-currency balances, create audit evidence, and feed account balances, statements, reconciliation, and reporting. Holds affect spendable balance and must be released or settled through traceable operations.

See also:

Object Relationships

The system follows a strict hierarchical and relational model to ensure data integrity and auditability.

Hierarchy Breakdown

  1. Control Ledgers: Represent categories in the Chart of Accounts (e.g., "Public Customer Deposits"). They aggregate balances from children but never hold individual customer funds directly — a control ledger that has any subledger under it stops accepting direct postings.
  2. Subledgers: An account or a customer can own several subledgers, one per purpose (Current, Hold, Fees receivable, Interest accrual, Collateral) and currency — see Why one customer has several subledgers below. Every account still gets its Current subledger automatically at opening; the rest open lazily, the first time each is actually needed.
  3. Customer Account: The user-facing entity. The account balance is a projection of its Current subledger specifically — the account never changes shape when a customer also picks up a Hold or Fees receivable subledger elsewhere.

Monetary Amount Format

All monetary amounts in API responses use the CcyAmtWithPrecision format. This self-describing format expresses amounts in minor/atomic units (e.g., cents for EUR, satoshi for BTC) as a string, alongside the currency code and precision.

{
  "amount": "123456",
  "currency": "EUR",
  "precision": 2
}
FieldTypeDescription
amountstringInteger in minor units (e.g., "123456" = 1234.56 EUR).
currencystringISO 4217 code for fiat or asset code for crypto.
precisionintNumber of decimal places (e.g., 2 for EUR, 8 for BTC, 0 for JPY).

To convert to a display value: displayAmount = amount / 10^precision.

This format is used for all balance, amount, and monetary fields including: balance_posted, balance_available, balance_pending, balance_lcy, overdraft_limit, total_amount, amount, amount_lcy, debit, credit, etc.


Balance Management Concepts

CoreBanq distinguishes between different balance states to support complex banking operations like "authorized but not settled" payments and administrative freezes.

Balance Types

TypeCalculationDescription
Posted BalanceSum(Credits) - Sum(Debits)The settled, legally recognized balance.
Pending BalancePosted + Expected Future EntriesIncludes entries that are authorized but not yet value-dated.
Available BalancePosted - Sum(Active Holds) - Pending DebitsThe "spendable" amount. This is what the user sees as their current buying power.

Balance Holds

Holds are administrative or system-driven restrictions on a ledger's available balance. Holds do not decrease the posted balance; they only reduce the spendable amount until they are either released or "settled" (converted into a real debit entry).

Hold Scenarios:

  • Card Authorizations: A merchant authorizes $50. A hold of $50 is placed.
  • Administrative Hold: Compliance department freezes $10,000 pending verification.
  • Overdraft Protection: Negative holds can be used to temporarily increase buying power.

API Reference

Ledger Management (V2)

GET /v1/ledgers

Returns a paginated list of ledgers. By default it lists Control Ledgers only (the Chart of Accounts view); subledgers are included only when explicitly requested.

GET /v1/ledgers/chart

Returns a balance-history time series for charting, not the Chart of Accounts tree. Each series is a list of {x, y} points (x = timestamp, y = balance) at the requested interval. The ledgers to plot are selected with the required search.code.in query parameter (a comma-separated list of ledger codes); an optional color seeds the series colour. Requesting no valid codes returns 400.

GET /v1/ledgers/{id}

Retrieve full details of any ledger (Control or Subledger) including current and available balances.

POST /v1/ledgers

Create a new Control Ledger. Note: Subledgers are managed automatically by the Account service.

Balance Holds (V2)

POST /v2/ledgers/holds

Place a new hold on a ledger. Decreases balance_available immediately.

GET /v2/accounts/{id}/holds

Retrieve all active holds for an account's subledger.

GET /v2/ledgers/holds/{id}

Get detailed information about a specific hold (reason, expiry, notes).

POST /v2/ledgers/holds/{id}/release

Release an active hold. Restores balance_available.


Technical Details

Automatic Subledger Creation

When a new Customer Account is created, the system executes an atomic transaction:

  1. Creates the Account record.
  2. Identifies the correct Control Ledger (Parent) based on currency and account type.
  3. Creates a Subledger linked to that parent.
  4. Updates the Account to reference this new Subledger.

Routing by customer type

Which control ledger a new account routes to is set directly on the control ledger's own properties — a Customer Types list (Corebanq Configurator → Ledger Browser → open the control ledger → "Customer Types"). A customer type + currency combination routes to exactly one control ledger; the system rejects assigning the same type + currency to a second ledger, so routing can never become ambiguous. This replaced an external configuration file — there is nothing to edit outside the ledger's own properties anymore.

Only a leaf control ledger — one with no child ledgers underneath it — can carry customer types. A parent or group ledger (e.g. the top-level "22" Customer Deposits group, or the "221" Type A Customer Deposits group) exists purely to aggregate its children's balances and can never itself receive an account booking, so it cannot carry a routing either; the Configurator hides the "Customer Types" control for such ledgers, and the API rejects the assignment if attempted directly. Set customer types on the specific currency leaf under the group instead (e.g. "2211" for a Type A customer's CHF deposits, not "221").

On a brand-new environment, the standard chart of accounts already ships with this routing — the public and exempt customer-deposit control ledgers come pre-assigned to their customer types the first time the chart is imported, so a fresh deploy can open accounts immediately without any manual setup.

Subledger description pattern

Subledgers are named automatically. By default, every control ledger produces descriptions like "Customer Deposits Liabilities - Type A Customer (EUR) - Customer ABC Ltd" — the control ledger's own description plus the customer's name — with nothing to configure. Admins only need to touch this when one specific ledger should read differently: open that control ledger's own properties (Corebanq Configurator → Ledger Browser → "Subledger Description Pattern") and set an override template, e.g. {parent_description} (Direct Client: {customer_name}). Clearing the field returns that ledger to the automatic default — there is no need to define the same pattern on every ledger just to get sensible naming.

Supported tokens: {parent_description} (the control ledger's own description), {customer_name}, {account_id_short}, {iban_suffix}. If an override references a token with no value for the account being opened, the legacy "Account {id}" naming is used instead — a partially rendered description is never posted to the books.

Why one customer has several subledgers

The Current subledger created above is only one of several a customer may end up with. Every franc, euro or dollar the bank holds for a customer lives in a subledger: an individual ledger account that belongs to exactly one customer (or one of their accounts) and rolls up into a bank-level control ledger. Regulation requires that client money be clearly identified in the bank's own accounting, per client — not merely as a pooled wallet total:

  • PSD2 Article 10 (safeguarding): client funds must be identifiable in accounting records and never commingled with any other person's funds.
  • FCA CASS 7.16.22E (individual client balance method): the firm keeps one balance per client, and may keep one per product or business line per client.
  • FCA CASS 15 / PS25/12 (in force 7 May 2026): records must distinguish relevant funds held for each client, support a daily internal reconciliation, a daily external reconciliation against the safeguarding bank, and a D+1 segregation check; a per-customer balance list (resolution pack) must be producible within 48 hours and records retained for 5 years.

A single account balance cannot separate "money the customer can spend" from "fees the customer owes the bank" or "funds reserved under a hold". Each of those is therefore its own subledger, each rolling into its own control ledger, so both the customer view and the bank's financial statements stay precise — and the safeguarding requirement can be computed directly from the ledger.

The structure: one customer, several accounts, several purposes

A customer may hold several accounts in the same currency (for example a main account and a payroll account, both CHF). Every account has its own Current subledger — the one created automatically above. Purposes that concern the relationship rather than a single account — such as fees receivable — are kept once per customer and currency:

The Fees receivable subledger is an asset (what the customer owes the bank), so it must roll into an asset receivables control ledger — never into fee income control 311, which would combine a receivable balance with earned revenue. The current chart does not yet seed such a receivables control, so the roll-up above is shown dashed and no live flow books the fees-receivable purpose until one is added and mapped (see Rollout note).

Reading the picture:

  • Account-level purposes (Current, Hold) attach to one account. Two same-currency accounts never share a Current subledger; each account's spendable and held money stays separately traceable.
  • Customer-level purposes (Fees receivable, collateral) attach to the customer. What Acme AG owes the bank in fees is one figure regardless of which account eventually pays it.
  • Control ledgers hold only summary balances. They are populated exclusively by the roll-up of their subledgers; manual journals against a control ledger are rejected. This mirrors long-standing core-banking practice and structurally prevents the most common cause of subledger-versus-general-ledger reconciliation breaks.
  • The sum of all subledgers under a control ledger always equals the control ledger's balance. This invariant is what the daily internal reconciliation verifies.

Codes in these examples. Account codes shown here (e.g. 2211 Type A CHF customer deposits, 311 Type A fee income) come from the standard Audax chart of accounts, grouped by leading digit: Group 1 Assets, Group 2 Liabilities, Group 3 Profit & Loss. The Fees receivable purpose is defined in the system, but the current chart does not yet seed a dedicated fees-receivable control ledger for its subledgers to roll into; until one is added, no live flow books to it (see Rollout note).

When each subledger is opened

Subledgers are opened lazily: only when the first booking of that purpose actually happens. Most customers never need a collateral subledger; none is created for them.

MomentWhat is openedAnchored to
Account openingCurrent subledger for the account's currencyThe account
First administrative or card hold on an accountHold subledgerThe account
First fee charged to the customer in a currencyFees receivable subledgerThe customer
First interest-bearing product on an accountInterest accrual subledgerThe account
First collateral pledge by the customerCollateral subledgerThe customer

The customer-facing account is unchanged by any of this: the IBAN, statements and the primary spendable balance continue to work exactly as before. Purpose subledgers are the bank's internal precision, surfaced to operations and reporting.

Booking walkthrough 1 — a monthly fee

Fees are booked in two steps, and the split matters for safeguarding: the moment a fee is charged, that money stops being client money (the requirement drops), even though the cash may briefly remain inside the safeguarding boundary until swept.

Step 1 — Accrual (fee falls due; customer has not yet paid):

LegSubledgerEffect
DebitFees receivable subledger (customer-level)The bank's claim on Acme AG increases
CreditFee income 311 (Type A revenues)Income is recognized

Step 2 — Settlement (collection from whichever account holds funds):

LegSubledgerEffect
DebitCurrent 2211-a1b2c3d4 (Main account)Customer's spendable money decreases
CreditFees receivable subledgerThe claim is cleared

Because the receivable is a real ledger line per customer, the fee queue, dunning and write-off decisions read directly from ledger balances — and the safeguarding calculation can exclude charged-but-unswept fees from the client-money requirement while the external reconciliation still sees the cash, exactly the classification the regulator expects.

If the customer holds several same-currency accounts, settlement may debit any funded account's Current subledger (primary first). The receivable side is unaffected: it is customer-level.

Booking walkthrough 2 — incoming funds and suspense

Safeguarding duties start when funds are received, not when they are allocated. An incoming payment that cannot be applied immediately (unknown reference, name mismatch) is booked to an inward suspense account (281 Suspense – IWT – SIC in the standard chart) — a bank-level internal account, not a customer subledger — so the money is on the books from minute one:

Regulatory anchors for this flow:

  • D+1 segregation check (CASS 15 / PSD2 Art. 10): funds received must reach a designated safeguarding account by close of the following business day. Because receipt is booked immediately, the daily D+1 check is a simple aging query over suspense and transit balances, with an audit trail of remediation postings.
  • Suspense discipline: suspense accounts are open-item managed — every entry carries a reference and must be reversed by a matching entry, netting to zero per item. Aged-item reports over suspense are a standing operations control; long-outstanding items are the classic early-warning signal auditors look for.
  • Individual client balances: the moment allocation happens, the money sits on the specific customer's Current subledger. The per-customer balance list required for the resolution pack is a direct ledger read, reproducible for any past business day from end-of-day balance snapshots.

Daily controls this structure enables

ControlFrequencyWhat it checks
Internal reconciliationEvery business daySum of client-money subledgers (requirement) vs sum of safeguarding mirror accounts (resource); shortfalls topped up from own funds, excesses swept out, same day
External reconciliationEvery business daySafeguarding mirror accounts vs the safeguarding bank's records
D+1 segregation checkEvery business dayNo client-attributable transit/suspense balance older than one business day
Suspense agingEvery business dayOpen suspense items by age, with owner and deadline
Control roll-up checkContinuousEach control ledger equals the sum of its subledgers

Negative individual balances are never netted against other clients when computing the requirement; they are excluded and surfaced separately as a funding obligation.

Rollout note

Existing accounts already have their Current subledger; nothing changed for them when multi-purpose subledgers went live. Purpose subledgers open lazily, the first time each is actually needed — the first hold, the first payment in transit, the first compliance action — never in advance and never simply because a customer is activated. A customer who is active for years without ever triggering a hold or a compliance action never gets one.

The mechanism described above — several subledgers per account or customer, opened lazily, rolling into their own control ledgers, with a control ledger refusing direct postings the moment it owns any subledger — is live today. No live flow has been moved onto a non-Current purpose yet (no product books to Hold, Fees receivable, Interest accrual or Collateral in production), so day-to-day behaviour is unchanged until a specific flow is migrated onto one. Safeguarding pool classification, end-of-day snapshots and the daily reconciliation views described above arrive in a second phase.

Identification Priority

For all entry and transfer endpoints, you can identify ledgers using:

  1. UUID (ledger_id): Most performant, immutable.
  2. Code (ledger_code): Human-readable (e.g., 2211-abc12345).
  3. Numeric ID (ledger_num_id): Legacy support.

The system resolves them in the order listed.

On this page