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