Skip to content
API Reference

API Reference

Is there an API, and what can it do? Yes: BigLedger’s REST API is served under /core2/, and this section is its reference. Every endpoint follows one shape:

/core2/{tnt|platform}/{dm|ms|cm}/<family>/<resource>/<access-endpoint>

The last segment is the access endpoint, and it names the caller the route was designed for — backoffice-ep for a signed-in back-office user, login-ep for an authenticated portal login, login-entity-ep for a customer or supplier acting on their own records, etl-ep for a server-to-server access key, and public-ep where an endpoint is deliberately unauthenticated. It is a naming convention rather than the authorisation check itself, which matters more than it sounds: see the two layers. Authentication covers the credentials; the Data API reference covers headers, paging, envelopes and limits.

How much API there is

The whole surface is derived from the backend’s controllers into a route table, so the numbers here are counted, not estimated — as at the backend commit named in the front matter, regenerated on 25 September 2026. At that commit the backend serves 18,720 routes from 2,218 controllers. 18,707 are under /core2/; the other 13 are a home page, a diagnostics endpoint, a short-link redirect and eight routes for the embedded web-chat widget.

By access endpoint: 1,191 routes are etl-ep — the server-to-server surface an integration uses (see the integration path) — and 9,491 are backoffice-ep, the surface the platform’s own applets call with a signed-in user’s token. The remaining 8,038 serve logins, public storefront pages, platform operation, and — 5,770 of them — carry no access segment at all. The figures move every time the backend adds a controller: on 15 September the same count read 18,630 routes and 1,116 etl-ep.

Those tallies classify a route by the segment in its path, which is a naming convention and not the authorisation check — see below before reading any of them as a limit on what your credential can reach.

Two references, and which one answers your question

There are two reference layers under this section, built by different methods, and they answer different questions. Neither is a draft of the other.

Module references — generatedERP Core API — hand-written
What it gives youEvery route, per controller: method, path, handler, and the file and line it is declared atSix resources in depth: request and response bodies, what each field means, what is required, the document lifecycle, and what a failure looks like
How it was madeRendered from a route table exported from the backend’s 2,216 Spring controllers at a named commitWritten from the backend, then verified by calling the live API — all 117 documented paths called, create, update and delete exercised on every resource, the test records removed afterwards
How complete it isComplete over one slice: routes whose path carries an etl-ep segment, plus read-only public-ep routes, for the controllers each page namesSix resources only, chosen because an integration needs them first. Deliberately not complete
How it goes wrongIt cannot drift — a regeneration fails if a page and the backend disagree — but it describes no behaviour at allIt is prose, so it goes stale when the product moves; it carries the commit and the date it was verified at

Read the generated page to find out whether a route exists, what it is called, and what else the same controller serves. Read the ERP Core page when you are about to write the call and need the body, the required fields and the failure modes. Then Data API for the things common to every call — hosts, headers, paging, the response envelope, limits.

The two layers do not partition the API

A route missing from the generated pages is not a route your access key is refused. The access segment in a path is a naming convention; the backend does not use it to decide which credential is accepted, and falls back in both directions:

  • an etl-ep handler that finds no usable AccessId/AccessKey pair tries the bearer token instead, so an etl-ep route also serves a signed-in user;
  • a request that carries no Authorization header at all falls through to the access-key interceptor, so a route with no etl-ep segment can still be called with an access key.

What decides the outcome is the permission the handler checks, which each ERP Core page lists per operation.

This is why the two layers do not line up. Until 17 September 2026 the sharpest case was chart of accounts, ledgers and cashbooks: their controllers declared no etl-ep route at all, so they appeared on no generated page, and they were reachable with an access key only on their plain paths. The backend now declares an etl-ep set for all three, and the Accounting API lists them. Their ERP Core pages still carry the bodies, the required fields and the failure modes.

What a call sets off after it answers

For example, a group whose online store pushes each paid web order into BigLedger as a sales invoice creates the document on .../gen-doc/internal-sales-invoices/etl-ep and then moves it to FINAL with PUT .../gen-doc/internal-sales-invoices/etl-ep/update-posting-status/{guid} — the same two steps the purchase invoice page walks through. The second call is the one that matters, and most of what it does happens after it has answered you:

  1. Before anything changes, the document is validated for posting. If validation fails, nothing is updated and nothing is queued — the document keeps the status it had.
  2. In one database transaction the status becomes FINAL and the company and branch running numbers are assigned. At the same moment the document is marked to skip e-invoicing if your request said so, or if its branch or its customer or supplier is set to skip. A request cannot switch that off, so when a finalised document never reaches LHDN, look at the branch and the entity before your payload — see the e-invoice module.
  3. Only then is the document handed to the primary job processor on the tenant’s queue, which is started asynchronously. Your 200 comes back without waiting for it. That processor fans out to the secondary processors that write the journal (financial accounting), the stock movement (inventory), membership points and the cashbook — and once the stock movement exists, the cost is computed and written back onto the document line.

So a 200 on the posting-status call means the document is final and numbered, not the journal exists. If you read the document back in the same second, its cost fields may still be empty; read it again once the queue has run. Two things must exist before you can do any of this: an access key, and a login subject behind it that holds the update permission for that document type — a key carries no scope of its own and acts as exactly the user it belongs to (Authentication). Whether to poll for the result or wait for a push is the question Webhooks answers, including the guarantees it does not offer.

Families, and which have a reference page

The family is the first segment after /core2/{tnt|platform}/{dm|ms|cm}/. The twenty largest, with what is documented today:

FamilyRoutesReference page today
erp — documents, entities, items, finance, e-invoice8,753The ERP Core API (chart of accounts, ledgers, cashbooks, suppliers, purchase invoices and payment vouchers, with request and response bodies verified against production); the eight module references below (its etl-ep and read-only public-ep surface, one table per controller); the E-Invoice API (16 back-office routes with request and response bodies); the Data API reference (19 etl-ep routes for generic documents, financial items and entities)
alg — the contact centre and bots1,077Unified Contact Center API (357 routes, 35 of 82 controllers)
crm817—
cms — content and storefront pages785—
dm — tenant-level records outside a module (branches, companies, labels)456—
wf — workflow and issues442—
pgw — payment gateways293Integrations API (payment providers and payment transactions, 10 etl-ep routes)
sfa — sales force automation283—
fi — finance outside erp272—
mrp — manufacturing271—
applet — applet registry and links267—
ecomsync — marketplace synchronisation256Integrations API — the connectors themselves serve backoffice-ep only and the page lists them as not exposed
del — delivery244—
dgmkt — digital marketing232—
hr203—
pyrll — payroll202—
identity — login, access keys, subjects206Authentication (login and access-key issue)
inv — inventory193Inventory API (2 etl-ep routes; the rest is backoffice-ep)
iam — permissions and roles189—
tpy — third-party services (e-signing, e-KYC, credit checks)183Integrations API — backoffice-ep only, listed as not exposed

A further 190 families — most of them platform-side and under fifty routes each — share the remaining 3,096. The full list, with a count per family, is in the same route table, which is not published; ask your BigLedger contact about a family this page does not name. Two of them have a page. Audit Trail API covers the six routes of applet-audit-trail, together with the six erp routes that serve the same record from a tenant’s own database, which is the surface behind the Tenant Admin applet’s Audit Trail screen. FPX E-Mandate API covers the eight FPX routes of paygw, the only way to create a direct-debit mandate, because no installable applet has a screen for it.

Module references

Eight module references and the error-code index, every one generated from the route table so that a path can only appear on a page if the backend serves it. Each page lists the etl-ep (server-to-server access key) routes and the read-only public-ep routes of its controllers, one table per controller, the {docType} slugs it covers where the generic-document controller is involved, and closes with what the family serves on backoffice-ep only and how many of its routes carry no access segment at all. Neither of those closing lists is a statement about what an access key can reach — see the two layers. The pages carry no behaviour prose: what a route does is the Data API reference’s and the integration notes by module’ territory.

PageRoutesControllersCovers
Accounting21430journals, subledgers, the chart of accounts, ledgers and cashbooks, tax transactions and filings, credit limits and terms, companies, branches and locations, payment and receipt vouchers
E-Invoice319documents submitted to LHDN, submission queues, LHDN integration, e-mail reports, PEPPOL
Sales17120entities, the generic-document controller with 42 sales document slugs, pricing, commission schemes
Inventory24920the item master, inventory items and transactions, stock takes, labels, warehouse item labels, attributes, 11 stock document slugs
Purchasing15016entities and the generic-document controller with 40 purchase document slugs
Reports82two sales reports; the 84 bi-reports routes and the financial reports are backoffice-ep only. Three more are documented by hand — see below.
Batch and Import13030CSV import files for customers, suppliers, employees, price books and nine document types; the JSON import queue
Integrations364marketplace item listings and fulfilments, payment gateways; the connector and third-party families are backoffice-ep only
Error Codes410 codes—every code value the API can return, with the 11 HTTP statuses the source declares

Not on the generated pages: Applet Reports API hand-documents three more routes — Sales Report By Document, Historical Stock Balance and Profit Loss Report. They merged to the backend on 2026-09-30, after the 25 September count above, and are rows in the route table at the pinned commit; the generated Reports page lists a fixed set of report controllers that does not include them, so this is the only place they are written down.

The integration surface — etl-ep plus read-only public-ep — is 1,425 routes at the 25 September commit (1,191 plus 234). When the eight pages were first generated on 15 September they covered 754 of the 1,349 then on it, and the Unified Contact Center pages a further 57. No page yet: the other contact-centre routes (Q-0396), cms, crm, the claims sub-family under erp, and the storefront reads (reviews, item views, catalogue search) — and two sets the backend added after that measurement: 48 etl-ep routes for e-invoices received from LHDN (the eight MyEInvoiceFromIrb… and XtnEInvoiceDocValidateFromIrbQueue controllers, six routes each) and six read routes for the webhook queue and its history (generic-webhook-queues, generic-webhook-histories). They are rows in the route table; no page here lists them yet, so open an issue before building on them. Anonymous write routes on public-ep are deliberately not documented anywhere.

What a route does, module by module, is in the hand-written integration notes by module and the membership endpoints.

When it goes wrong: symptom first

The full list of codes is the error index; these are the answers that send integrators the wrong way, because the status does not mean what it usually means.

What you seeWhat it means hereWhat to do
417 with SERVER_GENERAL_UNKNOWN_ERROR on a path you copied from a pageThe API answers every unhandled error with 417 — and a path that matches no route is one of them. There is no 404 for a missing route.Check the path against the module reference: dm against ms, singular against plural, the access segment. Then run the probe below.
400 with CLIENT_VALIDATION_GENERAL on a path you expected to be newEither the verb is wrong for that path, or your last segment landed on a {guid} variable and failed to parse as one. A 400 does not prove the route you meant exists.Check the verb, then probe with a sub-path no variable can absorb.
404 with CLIENT_VALIDATION_GUID_DOES_NOT_EXIST when finalising a document you can readThe posting-status handler answers a refused update permission the same way as a GUID that does not exist, or a {docType} slug it does not know.Confirm the GUID and the slug, then check the key’s login subject holds the update permission for that document type.
429 with CLIENT_OVERLOAD_DATABASEThe database ran out of connection slots. It is not a rate limit, and nothing retries for you.Back off and retry on your side; do not open more parallel calls.
200 on finalise, but no journal and empty cost fieldsThe processor chain runs after the response.Read the document back later rather than immediately.

How you know a route exists before you build on it

Send the request without credentials, to a path with a sub-path that no {guid} variable can swallow — .../etl-ep/query rather than .../etl-ep/something. Routing is decided before authentication, so the answer tells you about the path, not your key: 417 means no route, anything else means the path resolved. Run a control alongside it — the same call to a resource you know does not exist should answer 417. Without the control a 400 looks like success when it is only a failed GUID parse, which is exactly how a route that did not exist was once recorded as verified. This was established unauthenticated; an authenticated call to a missing route should behave the same way but has not been tested.

What is verified

The nine module references were unpublished on 6 September 2026 because they described endpoints that do not exist; the pages at those URLs today are the generated ones above. A cached copy of an old page is not a reference for anything.

Read next

The Data API reference — hosts, headers, paging, the response envelope and limits, which every call on every page above shares.

Last updated on