Reconciliation Periods
Periodic balance-sheet reconciliation (periodeavstemming) compares every balance-sheet account with something outside the ledger at the end of each period: the bank’s own balance for bank accounts, the filed VAT return for the VAT accounts, a document such as a loan statement, or — when nothing moved — a rule that says why the account needs no further documentation.
A reconciliation period is one sign-off span of a client account: a calendar year, a half-year or a VAT term, chosen by reconciliation_frequency on the client account settings (null reads as YEARLY; a change re-cuts the open periods on the next prepare, while reconciled periods keep their span). The records inside a period are ordinary external reconciliations whose ledger side is dated inside the span. The engine prepares them as drafts, reconciles the ones a rule or a matching source settles, and leaves the rest for a person. It never posts journal entries.
The feature is in early access: every endpoint returns 403 with code period_reconciliation.early_access_required unless early_access is enabled on the client account settings.
How a period fills up
Each period is checked scope by scope:
| Reconciler | Scope | Compared with | Reconciled automatically when |
|---|---|---|---|
BANK |
one house bank account per month-end | the balance imported through the bank integration (BANK_BALANCE) |
the ledger equals the bank |
VAT |
one VAT term ending in the period | the VAT settlement document of the approved return (VATRP, addressed without a line); the VAT accounts are expected to be empty |
the VAT accounts are empty |
BALANCE |
every other posted balance-sheet account at the period end | a document BALANCE line that documents the account, else the period itself (RECONCILIATION_PERIOD) |
no postings in the period, balance zero, or unchanged since last reconciled |
A scope is only written once it is ready. A bank month is ready when every transaction dated up to the month-end is matched to the ledger; until then the scope has no record and the API reports why (readiness_reason). Past the ajourhold deadline (the VAT filing date of the term, or four months after the month-end) the month is written anyway, with the unposted transactions as a reconciling item.
A period becomes RECONCILED on its own the moment it has ended and every scope has a non-draft record; reconciled_by_id is the person who reconciled the last record, or 2 when the engine did it. If a reconciled record later drifts — a posting into the period, a re-imported balance — the record is retired, a fresh draft takes its place and the period is REOPENED.
Preparation runs nightly for every early-access client, a few minutes after each posting, and on demand through POST /api/v2/reconciliation-periods. It is idempotent.
Endpoints
List Reconciliation Periods
GET /api/v2/reconciliation-periods?client_account_id=456
| Parameter | Type | Required | Description |
|---|---|---|---|
| client_account_id | integer | Yes | The client account |
| page, per_page | integer | No | Pagination (default 1 / 100) |
{
"data": [
{
"id": 18,
"client_account_id": 456,
"period_start": "2026-01-01",
"period_end": "2026-06-30",
"status": "RECONCILED",
"reconciled_at": "2026-07-03T03:31:12Z",
"reconciled_by_id": 2,
"created_at": "2026-05-02T03:30:00Z",
"created_by_id": 2
}
],
"meta": { "page": 1, "pages": 1, "per_page": 100, "records": 1 }
}
Prepare Reconciliation Periods
POST /api/v2/reconciliation-periods
Content-Type: application/json
{ "client_account_id": 456 }
Creates any missing periods up to the one containing today and brings every period up to date. Returns the client’s periods. Idempotent — use it as the page’s refresh.
Get Reconciliation Period
GET /api/v2/reconciliation-periods/18
Returns the period with its scopes: one entry per comparison, with the record when one exists.
{
"id": 18,
"period_start": "2026-01-01",
"period_end": "2026-06-30",
"status": "OPEN",
"scopes": [
{
"key": "BANK:24:2026-06-30",
"reconciler": "BANK",
"label": "DNB driftskonto 06.2026",
"as_of_date": "2026-06-30",
"is_ready": false,
"is_overdue": false,
"readiness_reason": "12 bank transactions not yet posted",
"external_reconciliation": null
},
{
"key": "BALANCE:1250:2026-06-30",
"reconciler": "BALANCE",
"label": "1250 Inventar",
"as_of_date": "2026-06-30",
"is_ready": true,
"is_overdue": false,
"readiness_reason": null,
"external_reconciliation": {
"id": 9001,
"is_draft": false,
"reconciliation_method": "NO_ACTIVITY",
"note": "No postings on the account in the period",
"expected_amount": "84000.000000",
"ledger_amount": "84000.000000",
"difference": "0.000000",
"entries": [ "…" ]
}
}
]
}
Reopen a Reconciliation Period
PATCH /api/v2/reconciliation-periods/18
Content-Type: application/json
{ "status": "REOPENED" }
The only manual transition. Completion is automatic.
Reconcile a Record
Drafts are edited and reconciled through the external reconciliation resource:
PATCH /api/v2/external-reconciliations/9002
Content-Type: application/json
{
"items": [ { "description": "Card settlement 14.06 posted 02.07", "amount": "4300.00" } ],
"is_draft": false
}
items replaces the draft’s reconciling items; is_draft: false reconciles it, which requires the items to explain the whole difference and both sides to be unchanged since the draft was prepared (409 period_reconciliation.stale_draft otherwise; the next prepare rebuilds the draft). The server sets reconciliation_method to EXTERNAL_MATCH or EXPLAINED.
Drafts of a period are listed with GET /api/v2/external-reconciliations?client_account_id=456&is_draft=true&as_of_from=2026-01-01&as_of_to=2026-06-30.
Attributes
| Attribute | Type | Description |
|---|---|---|
| id | integer | Unique identifier (read-only) |
| client_account_id | integer | The client account |
| period_start, period_end | date | The span; open periods follow the current frequency, reconciled ones keep the span they were reconciled under |
| status | string | OPEN, RECONCILED or REOPENED |
| reconciled_at | datetime | When the period completed (read-only) |
| reconciled_by_id | integer | Who reconciled the last record; 2 for the engine (read-only) |
Error Responses
| Code | Status | When |
|---|---|---|
| period_reconciliation.early_access_required | 403 | The client account is not in early access |
| period_reconciliation.not_a_draft | 400 | Reconciling a record that is not a draft |
| period_reconciliation.unexplained_difference | 400 | Reconciling a draft whose items do not cover the difference |
| period_reconciliation.stale_draft | 409 | The ledger moved since the draft was prepared |
| period_reconciliation.period_not_reconciled | 400 | Reopening a period that is not reconciled |
Related Resources
- External Reconciliations — the records inside a period
- Period Locks — suggested, never written, when a period completes
- Client Account Settings —
reconciliation_frequency,early_access