API endpoints

One page per resource, carrying both directions: what a write accepts and what a read answers. This page carries only what every resource shares.

The resources

A path below is relative to /api/v1; … stands for /organisations/{organisation}, because data with a figure or a month in it belongs to one company. A resource with no write path is read only.

ResourceWriting itReading itWhat it carries
Organisations-/organisationsThe companies the credential may read
Account types-/account-typesThe system account types an account carries
Sections-/sectionsThe section tree a statement is built from
Tags-/tagsThe accounting-standard tags an account can carry
Currencies-/currenciesThe group's currencies and its rate settings
KPIs-/kpis, …/kpi-valuesThe KPI names, and one KPI's figures
Periods and years-…/periods, …/yearsThe months and years a company can report
Accounts/accounts/accountsThe accounts, with the type each one reports under
Trial balance/trial-balances/trial-balancesOne month of debit and credit movement per account
Statements-…/statements/{statement}The profit and loss, the balance sheet and the cash flow
Invoices/invoices/invoicesSales documents with their lines
Bills/bills/billsPurchase documents with their lines
Journal lines/transactions/transactionsLedger lines, journal by journal
Operational data/operation-data/operation-data, …/{dataset}Figures for the dashboard and report blocks
Exchange rates-…/exchange-ratesThe rate between two currencies for a month
Consolidation-…/consolidation/{dataset}CTA, NCI, journal vouchers, adjustments and intercompany
Intercompany transactions-…/intercompany-transactionsThe elimination postings between the group's companies
Request history/requests/requestsWhat was sent, and what it wrote

A write also has /validate on the end of its path, which runs every check and writes nothing.

Scopes

A credential is given scopes, one per resource and action, and a token carries one ability per scope: scope:<resource>.<action>. A request whose credential holds no scope for it is refused with 403, before anything is read or written. A credential given only read scopes cannot write, and one given only write scopes cannot read.

ResourceWrite scopeRead scope
Organisations, account types, sections, tags, currencies, KPIs, periods and years-reference.read
Accountsaccounts.writeaccounts.read
Trial balancetrial_balance.writetrial_balance.read
Statements-statements.read
KPIs-kpis.read
Invoicesinvoices.writeinvoices.read
Billsbills.writebills.read
Journal linestransactions.writetransactions.read
Operational dataoperation_data.writeoperation_data.read
Exchange rates-exchange_rates.read
Consolidation-consolidation.read
Intercompany transactions-intercompany.read

Six resources are pairs - accounts, trial balance, invoices, bills, journal lines and operational data - and every other resource is read only. Every vocabulary shares one scope, reference.read, because a caller needs all of them before it can ask for a figure.

Writing: what every write shares

The URL names the resource. No wrapper noun, no verb. The company is always in the path, because data belongs to a company.

The body is an envelope: the declarations that apply to the whole payload, and the records themselves.

{
  "declarations": { "…": "…" },
  "records": [ { "…": "…" } ]
}
DeclarationWhat it means
source_referenceYour own id for the feed, 1–64 characters, required. Rows are held per source, so two feeds writing the same month do not overwrite each other.
modeWhat happens to stored rows the payload does not carry. The default differs by resource — each resource's page states its own.
webhook_urlCalled once when the request finishes or fails. Five second timeout; a slow endpoint of yours never delays the write.

Declarations about amounts — period, scenario, value_basis, rate_direction, base_currency — apply to every resource except accounts, which carries no month and no amounts.

The fields a resource accepts, and how it is read

GET /api/v1/schemas/accounts
GET /api/v1/schemas/consolidation

No token needed, so an integration can be built before a credential exists. For a resource a feed writes into, the answer is a JSON Schema of that resource's declarations and records, plus identity (which fields make two records the same record), record_limit (your group's own figure when the call carries a live token, the default otherwise), limits, and every error_codes entry.

The same answer states how the resource is read, under read: the scope it needs, the parameters it takes with their type and allowed values, and the fields it answers. A resource that is only read - statements, kpi-values, exchange-rates, consolidation, and the vocabularies - answers that contract alone. A parameter the contract does not state is refused by name, so what it states is exactly what the endpoint accepts.

A resource that does not exist answers 404 with the resources that do.

What a write answers

202 Accepted, with Location pointing at the request's own URL:

{
  "id": 87,
  "organisation_id": 141,
  "kind": "trial_balance",
  "source_reference": "netsuite-monthly",
  "period": "2026-09",
  "status": "written",
  "records_received": 412,
  "counts": { "created": 412, "updated": 0, "unchanged": 0, "rejected": 0 },
  "suppressed": 0,
  "warnings": [],
  "failure": null,
  "result": {},
  "recalculation": "pending",
  "written_at": "2026-10-23T06:14:02+00:00",
  "links": {
    "self": "…/organisations/149/requests/87",
    "results": "…/organisations/149/requests/87/results"
  }
}

status is written or failed. unchanged means the record was identical to what is already stored and nothing was written for it. recalculation is null for resources that do not recalculate the reports, and pending turning into done or failed at the request's own URL for those that do.

Send an Idempotency-Key header and a repeated request answers with the first one and writes nothing. Without it, a retried send is a second write — correct for a month sent whole, wrong for a payload that only adds.

Reading: what every read shares

Two levels. The vocabularies are shared by the whole group - the organisations, the account types, the sections, the tags, the currencies, the KPI names, and each company's periods and years. They are not under a company's path, because every company in that group answers them the same way. Everything that carries a figure belongs to one company, and its path names that company.

A company that is not yours answers 404. The API never confirms that another group's company exists, so not_found is the answer rather than 403.

Lists page the same way. Every list takes page and per_page (50 unless stated, at most 200) and answers data beside page, per_page, total and has_more. The record limit that applies to a write does not apply to a read; the requests-per-minute limit does.

A month is Mon-YYYY - Jul-2026 - in a read's parameters and in its answer, and a date is YYYY-MM-DD. Operational data is the one exception: its rows are stored and read as YYYY-MM, the same way a write states such a row's month.

A figure states what it is: its amount at stored precision, the currency it is presented in, its basis - movement, balance, debit or credit - its scenario and the period it belongs to. A caller never has to guess which basis it received.

A statement answers as the report draws it: the sections in order, each with its label and its amount, and the lines behind a section when ?detail=1 is asked for.

A read answers the same number as the screen. That is what the API is measured against: the same account, the same month and the same scenario answer one figure in a read and in a cell report.

A read is not a report. A report is a worksheet - cells, formulas, layouts, drills - and a caller that can read the accounts, the months, the statements and the figures can build its own view. Exporting to Excel or PDF, report images and report schedules are not part of the API.

The same reads are offered to an AI client as tools. Each tool is one of these reads for one company, with the same answers and the same refusals - see AI connectors (MCP).

Not available