Request history

Every write is kept as a request: what arrived, what came of it, and why anything was refused. These three endpoints read that record. Nothing is ever posted to them.

The endpoints

MethodPathAnswers
GET/api/v1/organisations/{organisation}/requests The last fifty requests, newest first
GET/api/v1/organisations/{organisation}/requests/{request} One request — the same body the write answered with, at its current state
GET/api/v1/organisations/{organisation}/requests/{request}/results The outcome of each record, by index

All three need a bearer token and a credential issued for that company. A request that belongs to another company answers 404, not 403: the API does not confirm that someone else's request exists.

The list

GET /api/v1/organisations/149/requests?kind=invoices&page=2&per_page=50
Authorization: Bearer {access_token}
{
  "requests": [
    {
      "id": 91,
      "kind": "invoices",
      "source_reference": "netsuite-ar",
      "period": "2026-09",
      "status": "written",
      "records_received": 34,
      "created_at": "2026-10-23T06:31:07+00:00"
    }
  ]
}

The answer carries page, per_page, total and has_more beside requests, so a caller can walk the history to its end:

{
  "requests": [ "…" ],
  "page": 2,
  "per_page": 50,
  "total": 137,
  "has_more": true
}
ParameterWhat it does
kindOne kind.
source_referenceOne feed.
periodOne month, YYYY-MM; only the kinds that carry a month can match.
page, per_pageNewest first, 50 to a page unless per_page says otherwise (at most 200).

A single request is still reachable by its id, whatever page it fell on.

One request

The same body the write answered with, kept current: recalculation reads pending, then done or failed.

FieldWhat it says
id, organisation_idWhich request, for which company.
kindaccounts, trial_balance, invoices, bills, transactions or operation_data.
source_reference, period, scenarioWhat the caller declared.
value_basis, rate_direction, base_currencyThe amount declarations, null for accounts.
modeWhat the payload replaced.
statuswritten or failed.
records_receivedHow many records arrived.
countsPer outcome: created, updated, unchanged, rejected.
suppressedLedger lines a document line already explains.
warningsAccepted, worth knowing. Never a refusal.
failurenull, or the code that failed with its detail.
resultKind-specific: for journal lines, the control_total comparison against the trial balance.
recalculationnull, or pending / done / failed for kinds that recalculate.
written_atWhen the records were stored.

The results

GET /api/v1/organisations/149/requests/91/results

{
  "request_id": 91,
  "status": "written",
  "records": [
    { "index": 0, "identity": "INV-10241", "outcome": "created", "errors": [], "warnings": [] },
    { "index": 1, "identity": "INV-10242", "outcome": "rejected",
      "errors": [{
        "kind": "invoices", "records_index": 1, "external_id": "INV-10242",
        "field": "lines.0.account_code", "code": "account_not_found",
        "detail": "The code 4999 is not in this organisation's accounts."
      }],
      "warnings": [] }
  ]
}

outcome is created, updated, unchanged or rejected. A rejected record did not stop the rest of the payload.

Every code a record can carry

CodeMeaning
required_field_missingA field the kind requires is missing.
unknown_fieldA field outside the published schema was sent; it is refused rather than stored.
invalid_typeA value is not the type the schema states.
invalid_valueA value is not one the schema allows.
account_not_foundThe code is not in this company's accounts.
duplicate_record_identityTwo records in one payload are the same record.
rate_required_for_foreign_currencyA document in another currency needs a rate.
rate_must_be_one_for_base_currencyA base-currency record states a rate of 1, or none.
journal_does_not_balanceThe journal's two sides differ.
line_requires_accountA document line must name an account code.
lines_are_requiredA document must carry at least one line.
month_held_by_another_sourceAnother source already holds the month.
period_lockedThe month is behind a period lock.
period_outside_windowThe month is outside the edition's allowed window.
base_currency_disagreesThe declared base currency is not the company's.
amount_disagrees_with_totalThe total disagrees with the lines by more than the tolerance.
record_rejected_by_writerThe write refused the record.

Status-level refusals — a dead credential, a company the credential was not issued for, a missing scope, a limit — are on Errors.

When the whole request fails

A body refused before anything is written answers 422 with errors and writes no request. A body that passed its checks and then failed while writing answers 422 with the code that failed, and stays readable at its own URL:

{ "message": "The request failed.",
  "failure": { "code": "journal_does_not_balance", "errors": [ … ] } }