Ledger and statements
The read surface over the book of record, on both APIs.The backend GL API - 7 routes
Every route requires a valid bearer (a service token or a Supabase JWT) or a trusted proxy identity. GL data is never exposed unauthenticated.GET /gl/meta
The filter vocabulary and the totals, in one call: orgs with their base currency, the distinct source types, periods and statuses, the whole chart of accounts, and {entries, debit_base, credit_base}.
GET /gl/entries
count is the unpaginated total, so a client can page without a second call.
GET /gl/entries/{entry_id}
The entry header - including its checksum and created_by - plus every line with its account code and name, native and base amounts, currency, and the activity and flow dimensions.
404 when the id is unknown.
This is the route that answers “who posted this, and what does it hash to”.
GET /gl/trial-balance
Every account with a movement, and the tie-out.
balanced is the assertion a book of record has to be able to make about itself.
GET /gl/reconciliation
The same tie in one row: debit_base, credit_base, net, balanced.
GET /gl/subledgers/{kind}
A thin sub-ledger view over a well-known control account.
404.
This is a GL movement view, not the AP/AR sub-ledger itself.
The real sub-ledger lives in
obligations, with a row per bill and per invoice, and that is what the control-account Close checksums tie against.
Do not read this route’s balance as “open AP by party”.POST /gl/sync-teable
The one operational route on this surface: posts approved operational records into the GL through the ledger engine.
Idempotent - safe to call repeatedly, on a schedule or after an approval.
The DevCenter operational read surfaces
Served from the canonical GL, with the UI’s response keys preserved exactly.Ledger - /gl
Fields with no canonical source - the source-payload id, the counterparty name, a transaction hop - are returned as
null, never invented.
GET /gl/reconciliation states plainly that no external source feed is wired rather than reporting a phantom break, and /gl/subledgers/ap labels its vendor from the entry description because that is the only counterparty label the GL itself carries.
Honest coverage beats a number with nothing behind it.Statements - /stmt
Computed live from the ledger by joining lines to accounts on type and normal side, and dating them by the entry date.
Balanced by construction, because they are a projection of a balanced book rather than a separate calculation.
On this chart, expense is
cogs + opex - there is no expense account type - and cash and bank are 1000, 1010 and 1030.
Transactions - /tx
The browsable layer between raw ingest and the ledger.
Dimensions - /dim
GET /dim/catalog - the dimension definitions and their hierarchical values, so the ledger and transaction views can render filterable dimensions.
Reconciliation - /recon
The human-in-the-loop rail: a suggested match is a proposal a human accepts or rejects.
Confidence stays internal.
The UI is given discrete states only, so a reviewer is never shown a score to defer to.
undo is the safety net that makes a mistaken accept recoverable.
The three mutating routes take the derived actor.
EPM - /epm
Portable Postgres queries over the dimensioned GL, deliberately not tied to one cube engine.
Schema resilience, and where it stops
The DevCenter’s read routers carry a wrapper that turns a missing legacy table or column into a200 with an empty body, so a gated UI page loads rather than crashing.
Aggregate endpoints are cached with a TTL, and POST /cache/invalidate drops that cache - called after the GL is re-posted so the statement numbers refresh immediately.
Where it is enforced
The test that would fail if it broke
backend/tests/test_gl_api.py for the canonical routes including the auth gate.
langgraph_chat/devcenter/tests/ for the read contract, including that every base-amount response carries base_currency.
Related
- Read the ledger - the same data in the UI
- How a journal entry is formed - what each entry in these responses is
- Statutory reporting - the TT200 projection over the same book
- Derived balances - why these totals are computed, not stored