Changelog
Consumer-facing changes, newest first.
Changes to the Accountflow API, newest first. Anything visible on the wire is listed here; deprecations follow the deprecation policy.
Unreleased
The API is in its pre-GA testing phase (1.0.0-rc), so this release still contains
breaking changes. Each one is listed first, with what to change on your side.
Breaking
- One naming rule. JSON fields, query parameters and path parameters are
camelCase. Renamed:pagination.nextCursorandpagination.hasMore(werenext_cursor,has_more); query parameterspageSizeandreconciliationStatus(werepage_size,reconciliation_status); webhook payload keysoccurredAtanddata.resourceType,data.resourceId,data.organizationId. Error codes andreasonvalues staysnake_case. Webhook signatures are unchanged. pageSizeoutside 1–200 is refused with400 validation_failedinstead of being silently clamped.- Actions are
POST …/actions/<verb>:/v1/companies/{companyId}/actions/restore,/v1/documents/{documentId}/actions/completeand/v1/documents/{documentId}/actions/restore(previously withoutactions/). DELETE /v1/companies/{companyId}takes no body. The optional audit note is the query parameter?reason=(up to 200 characters).- Access-policy rules carry
scopeType(COMPANY,ORGANIZATION,PORTFOLIO) and, for portfolio rules,portfolioId. Portfolio rules created in the application now grant exactly the portfolio's companies. - Reconciliation summary
approvalStatusisAPPROVED,REVOKEDor null; the valueSTALEno longer exists. - MCP sign-ins are for MCP. A token issued to an MCP client (sign-in through
Accountflow's login page) is accepted on
/mcponly; on/v1it is refused with403 capability_denied. Integrations use client credentials, as before. The scopes an MCP client may request are now the read scopes pluscontext:read(/.well-known/oauth-protected-resource/mcp); MCP sessions were already read-only. - API clients created in the application are bound to their service account. A
token must carry the service account's
subrecorded when the client was created; anything else is refused like an unknown client (401). - Webhook verification needs an HMAC answer. A new or re-pointed endpoint must
answer the
webhook.verificationrequest with a 2xx whose body contains the lowercase hexHMAC-SHA256(key = the endpoint's signing secret, message = challenge), for example{"challengeResponse": "<hex>"}. Echoing the challenge no longer verifies an endpoint. The webhooks guide has a test vector. - Document uploads must send the signed headers. The
PUTto the signed upload URL must carry every header in the newupload.headers(Content-Type,x-goog-content-length-rangeandx-goog-if-generation-match: 0). Storage refuses a body larger than the declaredsizeBytes, and the URL can create the file once but never replace it. - Write bodies refuse unknown fields. Company, access-policy, document,
webhook-endpoint and bank-reconciliation write bodies answer
400 validation_failedfor a property they do not define, instead of ignoring it. - New input limits on writes (
400 validation_failed, the limits are in the reference): companyname≤ 255,companyNumberandcompanyType≤ 32,countryCodetwo letters,obMonth1–12; access policies at most 500 rules, 1000accountIdsper rule,description≤ 2000; documentdisplayNameandmimeType≤ 255; webhookurl≤ 2048,description≤ 500, at most 100eventTypes; bank reconciliations at most 500transactionIdsand 500lineIds,note≤ 2000,period1–12. vatEnableddefaults tofalsewhen omitted on company create, as in the application (it defaulted totrue).list_account_statuscursors minted before this release answer400 invalid_cursor; start again from the first page.- Company automation follows the application's rules.
autoApprovecan only be on while automatic reconciliation is on — for the company (autoReconcile) and for each module on its ownenabled; a change that would leave it on beside switched-off automation answers400 validation_failedwithreason: auto_approve_requires_automation(turn both off in one change).SIMPLE_BANKandBALANCEmatch no lines and refuse amatchWindowDaysorsecondPassEnabledother than the one the settings already show (sending back the value you read changes nothing and is accepted). Either refusal'sparameternames the field as your request has it:autoApproveonPATCH …/settings/automation/modules/{module},automation.modules.<MODULE>.autoApprovein the combined settings change. Balance-template accounts are now their own module,BALANCE, in the settings response and onPATCH …/settings/automation/modules/BALANCE;GENERAL_LEDGERno longer stands for them. An unsetsecondPassMaxOpenLinesreads as 100, the value reconciliation uses (it read 70).
Added
analyzeon uploads.POST /v1/companies/{companyId}/documentstakes an optionalanalyze(defaulttrue). Where the company has document analysis switched on, a completed upload is read for its type and details;analyze: falsekeeps that file out. It cannot switch analysis on for a company that has it off.Uploads are scanned.
POST /v1/documents/{documentId}/actions/completenow checks the uploaded file against its declared type and scans it for malware before the document exists. A file of another type is refused with422 unprocessable, malware with the new422 malware_detected; either way the file is deleted and can be uploaded again to the same slot while its URL is valid. While the scanner is unavailable, completion answers503 service_unavailableand keeps the file: retry with the sameIdempotency-Key.Company settings.
GET /v1/companies/{companyId}/settings(and the MCP toolget_company_settings) returns a company's modules (VAT, payroll, fixed assets, intercompany), base currency, the people responsible for it (owner, controller, main accountant, auditor) and its automatic reconciliation — the company defaults and each module's overrides — with aversion. Changes are patches with an optionalexpectedVersion(409when the settings changed since; an approved Saga proposal must name it, as it must on every settings write):PATCH …/settings(modules, currency, responsible people — a person must belong to the company's organization and be able to read the company;resetunassigns the controller, main accountant or auditor, while the owner can be replaced but not removed),PATCH …/settings/automation(whether and how often reconciliation runs, matching tuning,autoPostOnHighConfidence,autoApprove) andPATCH …/settings/automation/modules/{module}(one module's overrides;resethands a field back to the company default).PATCH …/settingsalso takesautomation— the defaults and, inautomation.modules, each module's overrides — so one request changes any of a company's settings together, under oneexpectedVersion, or none of them. Every change is audited before and after. A company without settings yet reads as the defaults with its creator as owner — the owner its first write gives it. How the settings depend on each other is in docs/agents/company-settings-interactions.md.Account settings and routines.
GET /v1/companies/{companyId}/accounts/{accountNumber}/settings(MCPget_account_settings): the account's owner, documentation requirement, hidden, match window and its own automatic reconciliation values, with asettingsRevision.PATCH …/settingschanges them as a patch (resetclears a value or lets it inherit again;409whensettingsRevisionis not the current one), andPOST …/settings/actions/clear-automation-overridesreturns the account to the defaults.GET …/routineslists the routines that apply to the account, with acompanyRoutineVersion;POST …/routinewrites the company's own routine on it andDELETE …/routineremoves it, both with an optionalexpectedVersion(409when the company's routine changed since), andPATCH …/routines/{routineId}(with the routine'sversionas an optionalexpectedVersion) switches an organization's or portfolio's routine on or off for the account.Account template type and reconciliation rules.
PATCH …/accounts/{accountNumber}/settingsandget_account_settingsalso carry the account'stemplateType,matchRules(GENERAL_LEDGER accounts),balanceReconandsubledgerRecon(required for SUB_LEDGER accounts), validated as the application validates them;resetclears a rule. A match-rule regex may not use backreferences, lookaround or a repeated group that itself repeats.Company contacts.
GET /v1/companies/{companyId}/contacts(MCPlist_company_contacts;?includeInactive=trueadds deactivated ones) lists the people documentation requests go to, the default recipient first.POST …/contactsadds one,PATCH …/contacts/{contactId}changes one as a patch (an emptyphoneremoves it; an absentdefaultRecipientleaves it as it is), andPOST …/contacts/{contactId}/actions/deactivateand…/actions/reactivateswitch one off and on — a contact is never deleted, and a change never reactivates one. One default recipient per company: making another the default moves it, and the contact that stops being the default is audited too. An email can belong to one active contact (409 duplicate_resource). The list returns aversion; every contact write takes it as an optionalexpectedVersion(409when the contacts changed since).Account template choice.
GET /v1/companies/{companyId}/account-template(MCPget_company_account_template) returns the template the company uses — its own choice, or its organization's default — and the organization's templates.PATCH …/account-templatechooses one of them (accountTemplateId: nullfollows the default again), with an optionalexpectedVersionfrom the read. Choosing changes no account.Intercompany counterparty links. Under
/v1/companies/{companyId}/intercompany:GET …/groups(MCPlist_intercompany_groups) lists the groups the company belongs to and their members;GET …/definitions(list_intercompany_definitions,?includeInactive=trueadds deactivated ones) andGET …/definitions/{definitionId}return each link to a counterparty with its reconciliation lines, the accounts on each line and the counterparty's lines to pair with.POST …/definitionslinks a counterparty,PATCH …/definitions/{definitionId}changes the sign convention or partial settlement, or deactivates the link (active: false) — a link is never deleted, and a deactivated one keeps its accounts. Lines:POST …/definitions/{definitionId}/lines,PATCH …/lines/{lineId},DELETE …/lines/{lineId}(only an empty line, never the last). Accounts:POST …/definitions/{definitionId}/accountsputs an account, or one sub-ledger party or dimension value of it, on a line;PATCH …/accounts/{accountLinkId}moves it to another line;DELETE …/accounts/{accountLinkId}takes it off. Each part of an account belongs to one link:409 conflictwith areason(intercompany_account_owned,intercompany_account_shared,intercompany_account_split_differently,intercompany_slice_owned) names the link that has it. Each link carries aversion(its settings, lines and accounts) and the groups list one too; writes take them as an optionalexpectedVersion(409when the link or groups changed since).Chart mapping.
GET /v1/companies/{companyId}/standard-accounts(MCPlist_standard_accounts) lists the standard accounts of the company's country.PATCH …/accounts/{accountNumber}/mapping(map_account) maps an account to one of them andDELETE …/accounts/{accountNumber}/mapping?settingsRevision=(unmap_account) takes it off; both name the account'ssettingsRevision(409when it moved on). As in the application, a new standard account sets the account's reconciliation template, documentation requirement and rules, and a company that follows an account template gets the template's values for that standard account, except those it changed itself.POST …/account-mappingsmaps up to 500 accounts at once: a row that cannot be mapped is reported and the others are mapped.get_account_settingsnow names the account'sstandardAccount.Applying the account template.
GET /v1/companies/{companyId}/account-template/preview(MCPpreview_company_account_template) shows, account by account, what applying the company's account template would change, with theentryRevisionsit read and thewarningsto confirm (TEMPLATE_CHANGED,DOCUMENTATION_REQUIREMENT_REMOVED,AUTO_APPROVE_ENABLED).POST …/account-template/actions/applyapplies it — overwriting values the company changed itself — and lets the company's accounts follow the template from then on:409when the template changed since the preview,422(reason: confirmation_required, withwarnings) when a warning is not confirmed.GET …/accounts/{accountNumber}/template-provenance(MCPget_account_template_provenance) shows which template entry an account's values came from and which the company changed since;POST …/template-provenance/actions/restoretakes one value back from the template (settingsRevisionrequired). Apply and restore are not MCP tools.Scopes
settings:readandsettings:writefor company settings. An API client reads and changes them across its organization; a person (an MCP session) reads them with the application's settings-read right. Neither scope is part of the default grant. MCP sessions may requestsettings:read. Company updates (PATCH /v1/companies/{companyId}) and the company lifecycle (…/actions/disable|enable|restore,DELETE) now also check the application's roles whenever a person is behind the call; API clients are unchanged.Close and reconciliation status (reads). Under
/v1/companies/{companyId}:GET …/account-status(every account's reconciliation status for a period: balance, approved amount, deviation,status, filterable bystatusor account),GET …/accounts/{accountNumber}/reconciliation(one account's figures, its standing approval, adjustment lines, and whether the period can be approved now),GET …/approvals(sign-offs, including revoked ones, cursor-paginated),GET …/close-status(close percentage and close stages for a period; thevatstage is alwaysna, VAT status is not covered),GET …/work-queue(what is overdue or awaits a decision, most urgent first),GET …/blockers(what stops automation),GET …/deadlines(Norwegian regulatory deadlines in afrom/torange, default the next 90 days, at most 366) andGET …/data-freshness(when ERP data was last fetched, and what failed in the last 30 days). The same across a portfolio:GET /v1/portfolios/{portfolioId}/account-status,…/close-statusand…/work-queue(yearrequired; companies you cannot read are left out). Scopereconciliation:read;blockers,deadlinesanddata-freshnessneedcompanies:read. Also the MCP toolslist_account_status,get_account_reconciliation,list_approvals,get_close_status,list_work_queue,list_blockers,list_deadlines,get_data_freshness,list_portfolio_account_status,list_portfolio_close_statusandlist_portfolio_work_queue.Account and sub-ledger detail (reads). Under
/v1/companies/{companyId}:GET …/sub-ledgers/open-items(customer and supplier open items as of a date, with days overdue, aging buckets and totals),GET …/sub-ledgers/reconciliation(sub-ledgers against their control accounts: balances, difference, overlap and aBALANCED/BREAKverdict),GET …/settlements(which general-ledger lines were settled against each other, by a person or the automatcher),GET …/opening-balances(the lines behind an account's opening balance),GET …/accruals(the accruals on an accruals account that touch a period),GET …/reconciliation-adjustments(manual adjustment lines explaining an account-period's difference),GET …/account-activity(an account's history: approvals, comments, flags, settlements, accruals, setting changes),GET …/vouchers(voucher search) andGET …/fx-rates(the Norges Bank or ECB reference rate on a date). Scopeledger:readfor open items, opening balances, accruals, vouchers and FX rates,reconciliation:readfor the others. Account-scoped reads takeaccountNumber(withyear) or theaccountIdthe status reads return. Also the MCP toolslist_open_items,get_sub_ledger_reconciliation,list_settlements,list_opening_balances,list_accruals,list_reconciliation_adjustments,get_account_activity,search_vouchersandget_fx_rate, and, MCP only behindcontext:read,list_routine_sources(where an account's routines come from and how they changed).Snapshot tools (MCP only,
context:read).get_close_snapshot(close status, the top of the work queue, blockers, deadlines of the next 30 days, data freshness),get_account_snapshot(an account's settings, reconciliation, recent activity, settlements, comments, flags and documents for a period) andget_sub_ledger_snapshot(the sub-ledger reconciliation and the open items with aging at a month end) answer in one call what otherwise takes five to seven. Each part is exactly what the tool of the same name answers, within the scopes you hold: a part you cannot read is{"error": "<code>"}while the others still answer. List parts show the first rows andpagination.hasMore.More on existing reads, all additive:
- General-ledger lines: filters
taxCode,dateFrom/dateTo(posting date),amountMin/amountMax(signed) andvoucherNo; fieldssubLedgerKeys,dimensionKeys,settlementStatus(open,settled,partial),settlementId,settlementType(auto,manual) andattachmentCount. Cursors issued before stay valid. The first page (nocursor) carriestotalsover every line the filters match:lineCount,debit,credit(as a positive number) andnet; later pages havetotals: null. - Accounts:
templateType,reconciliationFrequency,documentationRequired, andownerandcontroller(user id and name). - Documents list: filters
search,associationType/associationId,periodYear/periodType/period,uploadedByanduploadedFrom/uploadedTo. A period without an association, orassociationIdwithoutassociationType, is400 validation_failed. - Comments:
mentions(userId,displayNameas written into the comment,startOffset,length). - Companies (list, get, and the company write responses):
modules(vat,payroll,assets), which modules the company uses according to its settings. A switch never set counts as VAT and payroll on, fixed assets off.
The new reads show people as user id and name only. Settling lines, adding adjustments, marking work-queue items and ordering automation are not part of the public API, and MCP stays read-only.
- General-ledger lines: filters
Comments, flags and accrual suggestions (reads).
GET /v1/companies/{companyId}/comments,GET /v1/companies/{companyId}/flags(both newest first, cursor-paginated, with subject filters) andGET /v1/companies/{companyId}/accrual-suggestions(pending suggestions with the exact schedule accepting would create). Scopeledger:read; also the MCP toolslist_comments,list_flagsandlist_accrual_suggestions. Writing comments and flags and deciding suggestions is not part of the public API, and MCP stays read-only.MCP tool schemas declare
requiredarguments and enumerations where the operation has them (todaycompanyIdon the three tools above,periodTypeanditemType).mode: DELEGATEDonGET /v1/whoami. A fourth principal mode for first-party internal services acting as the person named per request (X-Acting-User); it is not available to customers. TheX-Acting-Userheader on any other client is refused with400 validation_failed. Existing callers see no change.GET /v1/jobslists the jobs your client submitted, newest first, with an optionalstatusfilter.GET /v1/organizations/{organizationId}/users/{userId}/effective-access(scopeusers:read) returns a user's resulting access per company.The specification now describes every response you can get. Creates answer
201and asynchronous operations202;Idempotency-Keyis marked required; every schema declares its required fields and enumerations; each operation lists its error responses (401,403,404,409,413,422,429,503where they apply) and the response headers (X-Request-Id,RateLimit-Limit,RateLimit-Remaining,Retry-After,Idempotency-Replayed,Deprecation,Sunset). Problem documents document their extra fields (reason,errors,inUse,accountCodes,limit,jobId,retryAfterSeconds,requiredScope,parameter,supported), and everyerrors[]item has the same shape:{field, message, index?, allowedValues?}. Import amounts are documented as decimal strings; numbers are still accepted.Request bodies larger than 8 MiB are refused with
413 payload_too_large.Access-policy rules take
scopeTypeandportfolioIdon create and update, so a portfolio rule can be written and survives a rules replace. An update that would turn an existing portfolio rule into an organization-wide one (a rule with neitherscopeType,companyIdnorportfolioId) is refused with409 conflict,reason: portfolio_rule_would_widen; sendscopeType: ORGANIZATIONto mean it.Documents carry
associations: everything a document is attached to (company, transaction, account with its period, reconciliation run, ledger).associationkeeps its meaning (the first company or transaction association).
Fixed
- The settings patches require no field in the OpenAPI document.
resetonPATCH …/settingsandPATCH …/settings/automation/modules/{module}was listed as required although the API never needed it; absent fields stay unchanged, as documented. POST /v1/companiesandPATCH /v1/companies/{companyId}no longer fail with500in production. Creating a company switched on automatic reconciliation and updating one checked its payroll mappings, both through database triggers the API was not permitted to run.- MCP tool schemas list
companyId(andportfolioId) as required on every tool that is scoped to a company or portfolio. Thirteen older tools (get_account,list_vat_terms,get_trial_balance,list_accounts, the bank and reconciliation tools, …) left it optional in their schema although a call without it is refused withcompanyId is required. - Every operation that names a company, organization, portfolio or document checks access
to it before anything else: a request for one you cannot reach answers the uniform
404before its other fields are validated, and an MCP tool call that omits the id answers400 validation_failednaming it (some tools answered404). X-Request-Idis echoed only when it is 1–128 characters of letters, digits,.,_and-; any other value is replaced by a generated id (and that id is what support can find).- An organization that is deleted or deactivated is outside every client's and person's reach at once, including its sub-organizations and their companies.
- A write that failed after its effect could, in rare cases, run again on retry with
the same
Idempotency-Key; the stored response is now saved with the write itself. A retry of a request whose first attempt died mid-flight is accepted after 5 minutes instead of answering409 idempotency_in_flightuntil the key expired. - Companies:
GET /v1/companies/{companyId}for a company hidden from the API answers404instead of500. Two concurrent creates with the samecompanyNumberin one organization no longer both succeed. A company created, changed, disabled, enabled, deleted or restored through the API now reaches Accountflow's search like one changed in the application. - Documents: a document with more than one association no longer fails
GET /v1/documents/{documentId}or appears twice in lists. Download URLs serve exactly the file that was verified when the upload completed. - Bank: listing transactions no longer fails when a transaction has neither a booking
nor a value date (undated transactions come first).
POST …/bank/reconciliationsanswers409 conflictwithreason: already_reconciledand thetransactionIdswhen a bank transaction is already reconciled, and422naming thelineIdswhen a general-ledger line is not a current line ofperiodYearon the mapped account. The reconciliation summary counts periods from the company's fiscal-year start. - Approvals:
accountIdlists that account's own accounting year only (a differentyearis400), and ayear+periodfilter counts from the fiscal-year start. - Imports and corrections re-check the client, the company and the ledger when the job
starts, and fail with
api_client_inactive,company_unavailableorcompany_not_api_managedinstead of uploading. Keys.and..are refused. A409 job_in_flightnames thejobIdonly when you could poll that job. - Webhooks: the host is checked on the addresses actually connected to, so a DNS answer that changes between the check and the connection cannot reach a private address.
- Data freshness and blockers: failure messages no longer carry internal ids or e-mail addresses and are cut at 1000 characters. Account activity masks e-mail addresses inside values, not only in fields named for them.
- MCP (Saga):
trigger_erp_fetchandrun_automatchneed write access to the company;trigger_erp_fetchorders one accounting year at a time andrun_automatchat most 5 years (2000 to next year); a fetchingrun_automatchrespects the ERP's credit block and the 15-minute fetch window.create_settlementaccepts only the account's own, unsettled lines ofperiodYear's ledger, once each, within their amount (at most 500). A mentioned user must be able to read the company.flag_itemanswers409 conflictinstead of an internal error when the item changes concurrently. Every delegated write refuses unknown arguments and declares its limits in the tool schema.get_account_contextvalidatesaccountNumberas an account code, and an unreadable context bundle is503. Adjustments, work-queue state and automatch orders are now audited. - Documents: the document list now respects account-limited access. When the person a client acts for may only see some of a company's accounts, documents attached to the other accounts are left out.
- Imports and corrections: an import can no longer stay
runningindefinitely — an unexpected failure ends it asfailedwithfailureReasoninternal_error, and one that ran out of time ends asjob_expired; both are safe to re-send. Ids, keys and account codes may not contain/,{,}or whitespace (422). Importing into a year that belongs to another accounting system answers409 company_not_api_managed.inUse,sampleErrorsandfailureReasononly ever show your own ids. Large imports no longer delay other jobs. - Webhooks: deleting or auto-disabling an endpoint stops its queued retries (they appear
in the delivery log as
deadwithlastErrorstartingcancelled:). APATCHthat repeats the currenturlno longer re-runs verification, and aPATCHwithouturlworks again. Receiver responses are read up to 64 KiB. IPv6 private and reserved address ranges are refused like their IPv4 counterparts. - Access: archiving a policy, or removing a rule from it, now withdraws the access it
granted. Creating or updating a policy with an organization-wide rule works again.
API clients that act on behalf of a user are refused with
403 forbiddenonce that user is disabled or deleted. - Documents: completing an upload is limited to the client that created it.
- MCP: tool errors no longer include internal details; an argument the tool cannot read is reported by field name.
- Imports now finish the way an accounting-system sync does: the company's
last-updated timestamp moves and the usual follow-up processing runs. The import
result gains an additive
fetchCompletionobject (status:completed,failedwith afailureType,ignored,errororunreported); it never fails the import.
Earlier in this release
- Developer portal: agent skill. The overview page has an Add the API skill
button. It installs
accountflow-api, a skill for AI coding agents that carries the API's rules (auth, idempotency, retries, pagination, import order, refused deletions) with the specification and the guides bundled as references, generated per environment at/skills/accountflow-api.zip. The Imports section now appears in the navigation of every portal page. - Imports. Companies bound to the Api accounting system can receive their books
through the API (scope
imports:write). Six kinds, eachPOST /v1/companies/{companyId}/imports/<kind>with up to 10 000 lines, answering202with an import to poll atGET /v1/companies/{companyId}/imports/{importId}(GET /v1/companies/{companyId}/importslists them):accounts,dimensions,sub-ledgers,opening-balances,general-ledger-lines(merge byid;replaceis not available yet) andopen-items(withsourceDeletedand snapshot modes to retire items). Lines carry your ownid; general-ledger reads show it assourceLineId. Opening balances and general-ledger lines refuse account codes missing from the year's chart (422,reason: unknown_account_codes), periods are 1–12, one import per kind and company runs at a time (409,reason: job_in_flight), a company not bound to the Api system answers409,reason: company_not_api_managed, and more than 10 000 lines is413 payload_too_large. New eventimport.requested. - Corrections. What was pushed wrongly can be removed with the same scope and the
same 202-and-poll model:
POST …/imports/general-ledger-lines/deletionsandPOST …/imports/opening-balances/deletions({year, ids}), andDELETE /v1/companies/{companyId}/accounts/{accountNumber},…/dimensions/{key},…/sub-ledgers/{key}. Nothing that work in the application depends on is ever deleted, and nothing cascades: such a request answers409withreason(lines_in_use,opening_balances_in_use,account_in_use,dimension_in_use,sub_ledger_in_use) and aninUselist of your ids with what depends on each, and deletes nothing. Deleted lines keep their history. To change a line's values, re-send it with the sameid; to retire an account that has history, import it withhidden: true. New eventcorrection.requested. - Import readiness.
GET /v1/companies/{companyId}/imports/readinessis the preflight: whether the company is bound to the Api accounting system, what each year already holds,blockers,warningsand thenextStep. New guides: Importing data and Correcting data. - Dimension and sub-ledger reads.
GET /v1/companies/{companyId}/dimensionsand…/sub-ledgers(scopeledger:read; also the MCP toolslist_dimensionsandlist_sub_ledgers) list the keys general-ledger lines and open items refer to. - Context bundles (MCP only). Two tools,
get_company_contextandget_account_context, return what a company or a ledger account means: identity, standard-chart mapping and the routines the accountant registered, as compact Markdown withasOf,sourcesandsuggestedOperations. They exist on the MCP surface only, behind the scopecontext:read, which only an interactive session can hold; existing connectors must re-consent to pick the scope up. A bundle that is not ready yet is aservice_unavailabletool error asking you to retry, never a not-found. get_caller_identityanswers for humans too. Additive fieldsuserId(the person every authorization check runs as; null for system clients) and, for interactive sessions,organizationIds.- MCP endpoint (beta).
POST /mcpspeaks the Model Context Protocol over stateless streamable HTTP. Sign in as yourself (OAuth 2.1 authorization code + PKCE via the Accountflow login, consenting to exactly the scopes the client requests) and every read operation you could call over REST is available as a tool, scoped to your own access. The organization directory and access administration stay off the MCP surface (users:read,access:manage,webhooks:manageare not available to interactive sessions). Discovery follows RFC 9728: an unauthenticated call returns aWWW-Authenticatechallenge pointing at/.well-known/oauth-protected-resource/mcp. Mutations are not yet available over MCP. - Specification quality, no behavioural change: the published spec is OpenAPI
3.0.3, so nullable fields read as their declared type plus
nullable: true; the token endpoint is documented as the reference's first section, with its request form, token response and the OAuth 2.0 error shape; every success response declares its full body; free-form JSON fields (job parameters and results, webhook payloads) are published as free-form objects.
1.0.0-rc1 — 2026-08-20 (testing phase)
The complete /v1 surface, in pre-GA testing. The additive-only freeze
(deprecation policy) takes effect at GA; until then breaking changes remain
possible with ordinary review.
Surfaces
- Companies — read (disabled visible with
status, deleted 404), create, update, and the full lifecycle (disable / enable / delete / restore). - General ledger — chart of accounts, cursor-paginated GL lines with stable line ids, trial balance (opening, monthly movements, closing).
- VAT — filing terms with reconciliation status and decimal NOK totals.
- Users — organization membership reads and per-user effective access.
- Access management (system clients only) — policy documents with rules, assignment and revocation, applied automatically.
- Documents — two-step signed-URL uploads, signed downloads, metadata, lifecycle; binaries never pass through the API.
- Bank & reconciliation — accounts, transaction feed with computed reconciliation status, reconciliation groups, per-period summary, and the two mutations: reconcile and unmatch.
- Jobs — 202-and-poll for heavy operations, one in-flight per scope.
- Webhooks — signed thin events for every recorded change, verification handshake, retries with dead-lettering and auto-disable, delivery log.
Platform guarantees
- OAuth 2.0 (client credentials; authorization code + PKCE for interactive,
read-only for now),
resource:actionscopes. Idempotency-Keyon every mutation with byte-identical replays.- Opaque signed cursors; keyset pagination everywhere.
- RFC 9457 errors with a documented catalog.
- Rate plans: standard 300 req/min (burst 60), premium 1200 req/min (burst 240).