Accounts
Sends the accounts and answers them back. Every other kind names an account code, so this is the kind to send first and the read that says which codes exist.
Writing accounts
The endpoints
| Method | Path | What it does |
|---|---|---|
| POST | /api/v1/organisations/{organisation}/accounts |
Creates, updates, or leaves unchanged |
| POST | /api/v1/organisations/{organisation}/accounts/validate |
The same checks; nothing is written |
Needs a bearer token, a credential issued for that company, and the credential's
accounts.write scope.
The body
{
"declarations": {
"source_reference": "netsuite-coa",
"mode": "merge"
},
"records": [
{ "code": "4000", "name": "Sales", "type": "Income", "status": "active", "external_id": "ns-4000" },
{ "code": "1100", "name": "Trade receivables", "type": "Accounts Receivable" }
]
}
Declarations
| Declaration | Required | Value |
|---|---|---|
source_reference | yes | Your own id for the accounts feed, 1–64 characters. |
mode | no | merge (default) keeps codes the payload does not
carry; replace_all retires them. |
webhook_url | no | Called once when the request finishes or fails. |
Accounts carry no month and no amounts, so period, value_basis,
rate_direction and base_currency do not apply and are not asked for.
The fields
| Field | Type | Required | What it means |
|---|---|---|---|
code | string | yes | The account code. It is the record's identity. |
name | string | yes | The account name, stored exactly as sent. |
type | string | yes | A system account type by name —
Bank, Accounts Receivable, Other Expense and so on. A name that is
not a system account type is refused; it is never guessed from the account's name. |
status | string | no | Active unless stated. |
external_id | string | no | Your own id for the account, up to 128 characters. |
Any other field is refused as unknown_field rather than stored.
The system account types
type is one of these names, exactly as written. The class beside each one is how the reports read
it; the caller states the name, not the class.
| Type | Class |
|---|---|
BANK | ASSET |
ACCOUNTS RECEIVABLE | ASSET |
INVENTORY | ASSET |
CURRENT ASSET | ASSET |
FIXED ASSET | ASSET |
NON CURRENT ASSET | ASSET |
ACCOUNTS PAYABLE | LIABILITY |
CURRENT LIABILITY | LIABILITY |
NON CURRENT LIABILITY | LIABILITY |
TAXES PAYABLE | LIABILITY |
PAYROLL PAYABLE | LIABILITY |
EQUITY | EQUITY |
REVENUE | REVENUE |
OTHER INCOME | REVENUE |
INTEREST INCOME | REVENUE |
DIRECT COSTS | REVENUE |
EXPENSE | EXPENSE |
OTHER EXPENSE | EXPENSE |
DEPRECIATION | EXPENSE |
TAXES EXPENSE | EXPENSE |
INTEREST EXPENSE | EXPENSE |
NCI ALLOCATION | NCI ALLOCATION |
Names are matched without regard to case; a name outside this list is refused with
invalid_value.
The status values
status is Active or Inactive, and Active when it is not
stated. Anything else is refused with invalid_value. The recalculation marks an account
Inactive when no loaded month uses it, so a status that disagrees with the company's own
figures can change after the next load.
What it does
- Upsert by code. A new code is created, a changed name or type is updated, an identical
record is reported
unchangedand nothing is written for it. - A company, not the group. A request addressed at a consolidation parent is refused with
leaf_entities_only: a parent keeps no ledger, so it has no accounts of its own.
What it answers
{
"id": 84, "kind": "accounts", "source_reference": "netsuite-coa",
"status": "written", "records_received": 2,
"counts": { "created": 1, "updated": 0, "unchanged": 1, "rejected": 0 },
"period": null, "recalculation": null,
"written_at": "2026-10-23T06:02:11+00:00",
"links": { "self": "…/requests/84", "results": "…/requests/84/results" }
}
There is nothing to recalculate: accounts move no report figure. Under replace_all the answer
also carries result.retired: how many accounts the payload left out and were marked
Inactive. See Overview for the full answer and
Request history for reading it back.
Refusals
| Code | When |
|---|---|
invalid_value | type is not a system account type |
leaf_entities_only | The company is a consolidation parent |
duplicate_record_identity | Two records in the payload state the same
code |
unknown_field | A field outside the five above was sent |
required_field_missing | code, name or
type is absent |
A refused record never stops the rest: the request is written, that record is reported
rejected with its own code in the results.
Reading accounts
The accounts a company holds: the codes every other read names, with the type each one is reported under.
The endpoint
| Method | Path | Answers |
|---|---|---|
| GET | /api/v1/organisations/{organisation}/accounts |
Every account, one row each |
Needs a bearer token, a credential issued for that company, and the accounts.read scope.
The filters
| Parameter | What it does |
|---|---|
status | Active, Inactive, or absent for both. |
type | One system account type by name, such as BANK. |
code | One code. Unknown, it answers 404 rather than an empty
list. |
page, per_page | Paging, as everywhere. |
What it answers
{
"data": [
{
"code": "4000",
"name": "Sales Revenue",
"class": "REVENUE",
"type": "REVENUE",
"status": "Active",
"external_id": "ns-4000",
"tags": {
"ifrs_tag": null, "aasb_tag": null, "us_gaap_tag": null, "uk_gaap_tag": null,
"sfrs_tag": null, "local_gaap_flag": null
}
}
],
"page": 1, "per_page": 50, "total": 36, "has_more": false
}
| Field | What it says |
|---|---|
code | The code every other read names. It is the account's identity. |
name | The name as it was loaded, answered in clear. |
class | The statement class of the account's type: ASSET,
LIABILITY, EQUITY, REVENUE or EXPENSE. It is read
from the type rather than from a stored string, so every account answers the class its type is
reported under. |
type | The system account type by name, from Account types. It is always one of them, whatever the stored label says. |
status | Active or Inactive. The recalculation marks an
account Inactive when no loaded month uses it. |
external_id | The id the caller stated when it loaded the account, if it did. |
tags | One entry per standard's tag column - ifrs_tag,
aasb_tag, us_gaap_tag, uk_gaap_tag, sfrs_tag and
local_gaap_flag - carrying the tag value the account holds for that standard, or
null. The value is the part after the colon in a Tags id. |
Refusals
| Code | When |
|---|---|
not_found | The company is not one the credential may read, or the code is not one of the accounts |
invalid_value | status is neither Active nor
Inactive |
forbidden | The credential holds no accounts.read scope |
A type no account carries is not a refusal: it answers an empty list, because a filter narrows
and does not assert. A code is different - a caller naming one code is asking whether it
exists, so it answers 404.
Both directions name the same codes: what a read answers is what a write upserted, because the code is the identity.