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
| Method | Path | Answers |
|---|---|---|
| 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
}
| Parameter | What it does |
|---|---|
kind | One kind. |
source_reference | One feed. |
period | One month, YYYY-MM; only the kinds that carry a month can
match. |
page, per_page | Newest 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.
| Field | What it says |
|---|---|
id, organisation_id | Which request, for which company. |
kind | accounts, trial_balance, invoices,
bills, transactions or operation_data. |
source_reference, period, scenario | What the caller declared. |
value_basis, rate_direction, base_currency | The
amount declarations, null for accounts. |
mode | What the payload replaced. |
status | written or failed. |
records_received | How many records arrived. |
counts | Per outcome: created, updated, unchanged, rejected. |
suppressed | Ledger lines a document line already explains. |
warnings | Accepted, worth knowing. Never a refusal. |
failure | null, or the code that failed with its detail. |
result | Kind-specific: for journal lines, the
control_total comparison against the trial balance. |
recalculation | null, or pending / done /
failed for kinds that recalculate. |
written_at | When 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
| Code | Meaning |
|---|---|
required_field_missing | A field the kind requires is missing. |
unknown_field | A field outside the published schema was sent; it is refused rather than stored. |
invalid_type | A value is not the type the schema states. |
invalid_value | A value is not one the schema allows. |
account_not_found | The code is not in this company's accounts. |
duplicate_record_identity | Two records in one payload are the same record. |
rate_required_for_foreign_currency | A document in another currency needs a rate. |
rate_must_be_one_for_base_currency | A base-currency record states a rate of 1, or none. |
journal_does_not_balance | The journal's two sides differ. |
line_requires_account | A document line must name an account code. |
lines_are_required | A document must carry at least one line. |
month_held_by_another_source | Another source already holds the month. |
period_locked | The month is behind a period lock. |
period_outside_window | The month is outside the edition's allowed window. |
base_currency_disagrees | The declared base currency is not the company's. |
amount_disagrees_with_total | The total disagrees with the lines by more than the tolerance. |
record_rejected_by_writer | The 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": [ … ] } }