Trial balance

One month of debit and credit movement per account, written and read back. This is the data the reports read: a month written here is the month the statements, the drill and the dashboard show.

Writing a trial balance

The endpoints

MethodPathWhat it does
POST/api/v1/organisations/{organisation}/trial-balances Writes the month and recalculates
POST/api/v1/organisations/{organisation}/trial-balances/validate The same checks; nothing is written

Needs a bearer token, a credential issued for that company, and the credential's trial_balance.write scope.

The body

{
  "declarations": {
    "source_reference": "netsuite-monthly",
    "period": "2026-09",
    "value_basis": "company_base",
    "rate_direction": "document_to_base",
    "base_currency": "SGD",
    "mode": "replace_period"
  },
  "records": [
    { "account_code": "4000", "debit": 0, "credit": 12500.00 },
    { "account_code": "1100", "debit": 12500.00, "credit": 0 },
    { "account_code": "5000", "account_name": "Cost of sales", "debit": 800.00, "credit": 0 }
  ]
}

Declarations

DeclarationRequiredValue
source_referenceyesYour own id for the feed, 1–64 characters.
periodyesThe month, YYYY-MM. YYYY-MM-DD is read as that month.
value_basisyescompany_base for a trial balance — the amounts are already in the reporting currency.
rate_directionyesdocument_to_base or base_to_document; it applies to any rate a record states.
base_currencyyesThe company's reporting currency. A different one is refused with base_currency_disagrees.
scenarionoActual (default), Budget or Forecast.
modenoreplace_period (default), replace_all or merge.
switch_sourcenotrue states that this source takes the month over from the one holding it. Defaults to false.
webhook_urlnoCalled once when the request finishes or fails.

The fields

FieldTypeRequiredWhat it means
account_codestringyesThe code in this company's accounts. It is the record's identity.
account_namestringnoKept beside the code as a reader sees it.
debitnumbernoThe month's debit movement. Absent means zero.
creditnumbernoThe month's credit movement. Absent means zero.

A code the company does not hold is refused with account_not_found and the answer names the accounts kind. A trial balance never creates an account.

What it does

What it answers

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

A month sent twice with the same content reports unchanged for every record and moves no figure.

Refusals

CodeWhen
account_not_foundThe code is not in this company's accounts
month_held_by_another_sourceAnother source holds the month and the request does not switch source
period_lockedThe month is behind a period lock
period_outside_windowAn Actual month is outside the edition's allowed window
base_currency_disagreesThe declared currency is not the company's
invalid_valuescenario is none of Actual, Budget, Forecast; or a plan is sent to a level the group does not accept plan input at
duplicate_record_identityTwo records state the same account_code

A refused record never stops the rest: the request is written, that record is reported rejected with its own code in the results.

Reading the trial balance

One month of the ledger, account by account, with the movement and the closing balance the reports are built from.

The endpoint

MethodPathAnswers
GET/api/v1/organisations/{organisation}/trial-balances Every account's figures for the month

Needs a bearer token, a credential issued for that company, and the trial_balance.read scope.

The parameters

ParameterWhat it does
periodThe month. Either spelling is accepted, Jul-2026 or 2026-07; the answer states the label, Mon-YYYY. Absent, the company's reporting month is answered.
number_of_monthsHow many trailing months to answer, 1 to 120. Default 1.
currencyThe currency to present in, three letters. Default: the company's own. A currency the group holds no rate for is refused rather than answered untranslated.
scenarioActual, Budget or Forecast. Default Actual. A plan scenario answers the plan rows of that scenario, which is what a Budget or Forecast write stores.
account_codeOne account, instead of the whole ledger. A code that is not there answers an empty list, not 404: a filter narrows and does not assert.

What it answers

GET /api/v1/organisations/149/trial-balances?period=Jul-2026

{
  "data": [
    {
      "code": "SA-1000", "name": "Bank", "period": "Jul-2026", "scenario": "Actual",
      "debit": 125000.0, "credit": 40000.0,
      "debit_ytd": 700000.0, "credit_ytd": 650000.0,
      "movement": 85000.0, "balance": 250000.0, "average": 250000.0
    }
  ],
  "page": 1, "per_page": 50, "total": 33, "has_more": false
}
FieldWhat it says
code, nameThe account, as the accounts hold it.
period, scenarioWhich month and which version of the figures.
debit, creditThe month's movement on each side, as the ledger recorded them: both are unsigned, so the side is not lost in the sign.
debit_ytd, credit_ytdThe year-to-date movement on each side.
movementThe month's movement on the account's own normal side: positive when it moved the way the account usually moves. It is the figure a profit and loss line reads.
balanceThe closing balance at the month end, on the same normal side: the position the account stands at, and the figure a balance sheet line reads.
averageThe mid-month balance, balance - movement / 2, which a profit and loss balance is translated at with the average rate.

Amounts are answered at stored precision in the currency asked for; ask for the company's own currency and nothing is translated. Every amount belongs to the month in period on the same row - a row is one account in one month, and the months run oldest first.

The signs are the ones the statements answer in. A bank account holding a debit answers a positive balance here and a positive line on the balance sheet, so the two add up without a caller flipping one of them; a liability carries a positive figure on its own side too. To read the ledger the way the accounting equation does, use debit and credit, which are always unsigned.