Menu
Cookbooks
API reference
- Overview
- Companies
- Customers
- Invoices
- Articles
- Suppliers
- Supplier invoices
- Supplier payment files
- Expense claims
- Transactions
- Reconciliation
- Bank accounts
- Journal entries
- Voucher gap explanations
- Fiscal periods
- Accounts
- Fixed assets
- Documents
- Inbox items
- Dimensions
- Employees
- Salary runs
- Reports
- Imports
- Compliance check
- Skatteverket
- Peppol
- Webhooks
- Operations
- Health
Fiscal periods
Fiscal years and their lifecycle: create, edit, lock, unlock, close, year-end, opening balances, FX revaluation, and klarmarkering of years closed in a previous system.
Endpoints
GET/api/v1/companies/:companyId/fiscal-periods: List fiscal periods (räkenskapsår).GET/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/ixbrl: The K2 årsredovisning as an inline XBRL (XHTML) document.GET/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/ixbrl/validate: Pre-flight the generated iXBRL årsredovisning against Bolagsverket's kontrollera rules.GET/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/pdf: The årsredovisning as PDF: the live draft or a frozen version.GET/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures: The årsredovisning signer roster and its signatures.POST/api/v1/companies/:companyId/fiscal-periods: Create a fiscal year (räkenskapsår).POST/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/narrative: Edit the årsredovisning texts: förvaltningsberättelse, resultatdisposition, disclosure notes and K3 note texts.POST/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures: Add a board member or the VD to the årsredovisning signer roster.POST/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/versions: Freeze an immutable årsredovisning version: a draft snapshot, or the version that gets signed.POST/api/v1/companies/:companyId/fiscal-periods/:id/close: Close a fiscal period (IRREVERSIBLE per BFL 5 kap 8 §).POST/api/v1/companies/:companyId/fiscal-periods/:id/close-external: Mark a migrated fiscal year as closed in the previous system (klarmarkera).POST/api/v1/companies/:companyId/fiscal-periods/:id/currency-revaluation: Run FX revaluation for the fiscal period.POST/api/v1/companies/:companyId/fiscal-periods/:id/lock: Lock a fiscal period (no new entries can be posted into it).POST/api/v1/companies/:companyId/fiscal-periods/:id/opening-balances: Generate opening-balance verifikation for the next fiscal period.POST/api/v1/companies/:companyId/fiscal-periods/:id/opening-balances/correct: Correct a year's ingående balanser by storno: the full corrected IB replaces the old one.POST/api/v1/companies/:companyId/fiscal-periods/:id/opening-balances/manual: Book a fiscal year's ingående balanser (IB) from explicit lines, for a company new to Accounted.POST/api/v1/companies/:companyId/fiscal-periods/:id/reopen-external: Undo klarmarkera: reopen a year marked closed in the previous system.POST/api/v1/companies/:companyId/fiscal-periods/:id/unlock: Unlock a locked (not closed) fiscal year.POST/api/v1/companies/:companyId/fiscal-periods/:id/year-end: Execute year-end closing (currency revaluation + closing entry).PATCH/api/v1/companies/:companyId/fiscal-periods/:id: Rename or re-date an open fiscal year.PATCH/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/compliance: Answer the årsredovisning compliance questions and record the confirmations.PATCH/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures/:signatureId: Record that a signer signed the frozen årsredovisning version, or declined.DELETE/api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures/:signatureId: Remove a signer from the årsredovisning roster before a version binds it.
GET /api/v1/companies/:companyId/fiscal-periods
fiscal-periods.list · scope reports:read
List fiscal periods (räkenskapsår).
Returns every fiscal period for the company ordered by period_start DESC. is_closed=true means bokslut has been signed; locked_at non-null means writes are blocked at the DB-trigger level.
Use when: You need to find the active period before booking, build a year-selector UI, or audit the period-lock history.
Don't use for: Creating, editing, locking or closing periods: use POST /fiscal-periods, PATCH /fiscal-periods/{id}, POST /fiscal-periods/{id}/lock, /unlock, /close and /year-end.
Pitfalls
- previous_period_id chains the bokslut continuity (BFNAR 2013:2). A null value on a non-first period is a data-quality red flag.
- A period can be locked but not closed (löpande bokföring of the new year while bokslut work continues on the prior year: see BFL 5 kap 2 § for the löpande bokföring deadline).
- BFL 3 kap caps a single fiscal period at 18 months. First-year exceptions are allowed.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Response fields
| Name | Type |
|---|---|
fiscal_periods[].id | string |
fiscal_periods[].name | string |
fiscal_periods[].period_start | string |
fiscal_periods[].period_end | string |
fiscal_periods[].is_closed | boolean |
fiscal_periods[].closed_at | string | null |
fiscal_periods[].locked_at | string | null |
fiscal_periods[].previous_period_id | string | null |
fiscal_periods[].created_at | string |
fiscal_periods[].duration_days | number |
fiscal_periods[].exceeds_18_months | boolean |
Example response
{
"data": {
"fiscal_periods": [
{
"id": "fp_2026",
"name": "Räkenskapsår 2026",
"period_start": "2026-01-01",
"period_end": "2026-12-31",
"is_closed": false,
"locked_at": null
}
]
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
GET /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/ixbrl
arsredovisning.ixbrl · scope reports:read
The K2 årsredovisning as an inline XBRL (XHTML) document.
Generates the iXBRL document Bolagsverket's digital filing takes (K2, Bolagsverket taxonomy), for the live draft or a frozen version (version_id). The XHTML is also the human-readable document. It is not a filing: digital filing goes through connected software with the fastställelseintyg signed by BankID, which this API does not do.
Use when: Archiving the digital document, or validating it with external tools.
Don't use for: The pre-flight result as JSON (GET .../arsredovisning/ixbrl/validate) or a printable copy (GET .../arsredovisning/pdf).
Pitfalls
- K2 aktiebolag only.
- The live draft is refused while an SIE import is unfinished (409); a frozen version stays readable.
- proposed_dividend (whole SEK) applies to the live draft only.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
version_id | string | no | A frozen version (annual_report_version_id); omit for the live draft. |
proposed_dividend | number | no | Live draft only: proposed dividend in whole SEK for the resultatdisposition. |
Example response
{
"_note": "Returns application/xhtml+xml as a binary download."
}
GET /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/ixbrl/validate
arsredovisning.validate-ixbrl · scope reports:read
Pre-flight the generated iXBRL årsredovisning against Bolagsverket's kontrollera rules.
Generates the K2 inline XBRL document (the live draft, or a frozen version with version_id) and runs the local mirror of Bolagsverket's kontrollera checks on it, plus a generation dry run and the 5 MB size limit. Issues carry the Bolagsverket code where one exists (e.g. 1107 missing signers) or ACC-*. Nothing is sent to Bolagsverket. Read-only.
Use when: Before a digital filing, or to see why the iXBRL document is not ready.
Don't use for: The ÅRL/K2 completeness checks per stage (gnubok_validate_arsredovisning), or the document itself (GET .../arsredovisning/ixbrl, v1 only).
Pitfalls
- K2 aktiebolag only: the iXBRL generator does not produce K3 documents.
- A validation with issues still answers 200; read ok and error_count.
- An unknown version_id answers 404 NOT_FOUND.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
version_id | string | no | A frozen version (annual_report_version_id); omit for the live draft. |
proposed_dividend | number | no | Live draft only: proposed dividend in whole SEK for the resultatdisposition. |
Response fields
| Name | Type |
|---|---|
ok | boolean |
issues | object[] |
error_count | number |
warning_count | number |
generated_bytes | number |
entry_point | string |
period | object |
annual_report_version_id | string | null |
Example request
{
"fiscal_period_id": "7c2b…"
}
Example response
{
"data": {
"ok": false,
"issues": [
{
"code": "1107",
"severity": "error",
"message": "Underskrifter saknas."
}
],
"error_count": 1,
"warning_count": 0,
"generated_bytes": 84211,
"entry_point": "k2-ab-risbs-2024-09-12",
"period": {
"start": "2026-01-01",
"end": "2026-12-31"
},
"annual_report_version_id": null
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
GET /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/pdf
arsredovisning.pdf · scope reports:read
The årsredovisning as PDF: the live draft or a frozen version.
Renders the årsredovisning for the räkenskapsår (K2 or K3 template by the framework) as the dashboard does. Without version_id it is the live draft from the books, named ...-utkast.pdf; with version_id it is that immutable version with the signatures recorded on it, named ...-papperskopia.pdf once signed. Nothing is sent to Bolagsverket.
Use when: A printable copy for the board to sign on paper, the archive, or a review.
Don't use for: The inline XBRL document for digital filing (GET .../arsredovisning/ixbrl) or the report as JSON (gnubok_preview_arsredovisning).
Pitfalls
- The live draft is refused while an SIE import is unfinished (409); a frozen version stays readable.
- An unknown version_id answers 404 NOT_FOUND.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
version_id | string | no | A frozen version (annual_report_version_id); omit for the live draft. |
Example response
{
"_note": "Returns application/pdf as a binary download."
}
GET /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures
arsredovisning.list-signatories · scope reports:read
The årsredovisning signer roster and its signatures.
The current signer slots for the räkenskapsår: the unbound pending roster while one exists, otherwise the slots bound to the latest version with their status, signing date, method and evidence reference. The signature_id values are what PATCH and DELETE .../signatures/{signatureId} take; finalizing a version may create new slots bound to it. Read-only.
Use when: Before adding a signer (avoid duplicates) or to find the slot to record a signature on after a version is finalized.
Don't use for: The report content (gnubok_preview_arsredovisning) or the version list (gnubok_list_arsredovisning_versions).
Pitfalls
- Declined slots are listed too; they do not appear in the document.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Response fields
| Name | Type | Description |
|---|---|---|
signatures[].signature_id | string | |
signatures[].fiscal_period_id | string | |
signatures[].annual_report_version_id | string | null | Null while the slot is on the unbound roster. |
signatures[].role | string | |
signatures[].signer_name | string | |
signatures[].status | "pending" | "signed" | "declined" | |
signatures[].signed_at | string | null | |
signatures[].signing_method | "paper_original" | "advanced_e_signature" | "bankid" | "bolagsverket" | null | |
signatures[].evidence_reference | string | null | |
signatures[].evidence_recorded_at | string | null | |
signatures[].created_at | string |
Example response
{
"data": {
"signatures": [
{
"signature_id": "5b1c…",
"fiscal_period_id": "7c2b…",
"annual_report_version_id": null,
"role": "Styrelseledamot",
"signer_name": "Anna Andersson",
"status": "pending",
"signed_at": null,
"signing_method": null,
"evidence_reference": null,
"evidence_recorded_at": null,
"created_at": "2027-03-02T09:00:00Z"
}
]
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods
fiscal-periods.create · scope bookkeeping:write
Create a fiscal year (räkenskapsår).
Creates a räkenskapsår and links it into the continuity chain (previous_period_id, BFNAR 2013:2). The year must be at most 18 months, end on a month end, and start on the 1st unless it becomes the earliest year (BFL 3 kap. 1 and 3 §§). It must be contiguous with its neighbours: appended, it starts the day after the latest year ends; filling a gap, it also ends the day before the next year starts; prepended, it ends the day before the earliest year starts. A still-open prior year does not block: the 201 carries a PRIOR_FISCAL_YEAR_STILL_OPEN warning. Idempotent. Dry-runnable.
Use when: The company needs the next räkenskapsår to book in (e.g. January arrives), or an earlier year must exist before its SIE file or opening balances can be imported.
Don't use for: Closing the prior year (run the year-end), or changing an existing year (PATCH /fiscal-periods/{id}).
Pitfalls
- A start that does not continue the preceding year answers 400 FISCAL_PERIOD_NOT_CONTIGUOUS with details.expected_start (or details.expected_end): retry with that date.
- Overlapping an existing year answers 409 FISCAL_PERIOD_OVERLAP.
- An enskild firma normally runs the calendar year; a brutet räkenskapsår needs Skatteverket's permission.
- There is no delete: a wrong year can be re-dated with PATCH only while nothing is posted in it.
Risk: medium · Idempotent: yes · Reversible: no · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name, e.g. "Räkenskapsår 2027". |
period_start | string | yes | First day, YYYY-MM-DD. |
period_end | string | yes | Last day, YYYY-MM-DD (a month end). |
Response fields
| Name | Type |
|---|---|
fiscal_period | object |
Example request
{
"name": "Räkenskapsår 2027",
"period_start": "2027-01-01",
"period_end": "2027-12-31"
}
Example response
{
"data": {
"fiscal_period": {
"id": "a8f1…",
"name": "Räkenskapsår 2027",
"period_start": "2027-01-01",
"period_end": "2027-12-31",
"is_closed": false,
"closed_at": null,
"closed_externally": false,
"locked_at": null,
"previous_period_id": "5c2e…",
"created_at": "2026-12-01T09:00:00Z"
}
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/narrative
arsredovisning.update-narrative · scope bookkeeping:write
Edit the årsredovisning texts: förvaltningsberättelse, resultatdisposition, disclosure notes and K3 note texts.
Saves the narrative overrides for a räkenskapsår's årsredovisning, as the dashboard's text step does. Only the fields sent change; null clears a field back to the generated text. Covers the förvaltningsberättelse (description, important_events), the resultatdisposition text and proposed_dividend, the årsstämma date and decision, the ÅRL 5 kap. disclosures (long-term debt, ställda säkerheter, eventualförpliktelser), koncernförhållanden, a manual medelantal anställda, K3 note texts (note_overrides replaces the whole object) and the K3 kassaflödesanalys omission. A save clears the narrative confirmation in the compliance profile. Allowed after the period is closed; refused once a Bolagsverket submission is registrerad. Idempotent. Dry-runnable.
Use when: Writing or correcting the texts of the årsredovisning before a version is frozen for signing.
Don't use for: The compliance profile answers (PATCH .../arsredovisning/compliance), the figures (they come from the books), or freezing the document (POST .../arsredovisning/versions).
Pitfalls
- A version already frozen keeps its text: freeze a new version after editing.
- agm_disposition_outcome alternative_decision needs agm_disposition_decision text (400 VALIDATION_ERROR).
- parent_company_org_number is an organisationsnummer or a foreign registration id; a personnummer is refused.
- Registered at Bolagsverket: 409 ARSREDOVISNING_REGISTERED.
- Saving clears narrative_confirmed: confirm again with PATCH .../compliance {"narrative_confirmed": true}.
Risk: medium · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
description | string | null | no | Förvaltningsberättelse: allmänt om verksamheten. |
important_events | string | null | no | Förvaltningsberättelse: väsentliga händelser under räkenskapsåret. |
resultatdisposition | string | null | no | Styrelsens förslag till resultatdisposition, as text. |
proposed_dividend | number | null | no | Föreslagen utdelning in SEK (rounded to öre); null clears it. |
agm_date | string | null | no | Årsstämmans datum, YYYY-MM-DD (fills the fastställelseintyg). |
long_term_debt_over_five_years | number | null | no | ÅRL 5:13 §: long-term debt falling due after more than five years, SEK. |
securities_pledged | string | null | no | ÅRL 5:14 §: ställda säkerheter. |
contingent_liabilities | string | null | no | ÅRL 5:15 §: eventualförpliktelser. |
parent_company_name | string | null | no | Moderföretagets namn (koncernförhållanden). |
parent_company_org_number | "" | string | null | no | Moderföretagets organisationsnummer or foreign registration id; never a personnummer. |
parent_company_city | string | null | no | Moderföretagets säte. |
medelantal_anstallda_override | number | null | no | ÅRL 5:20 §: medelantal anställda as a whole number; null uses the computed average. |
long_term_debt_over_five_years_confirmed | boolean | no | |
securities_pledged_confirmed | boolean | no | |
contingent_liabilities_confirmed | boolean | no | |
parent_company_confirmed | boolean | no | |
agm_disposition_outcome | "proposal_approved" | "alternative_decision" | null | no | What the årsstämma decided about the resultatdisposition. |
agm_disposition_decision | string | null | no | The årsstämma's alternative decision, required with alternative_decision. |
note_overrides | object | no | K3 note texts by note key; the whole object is replaced, blank or null resets a note. |
omit_kassaflodesanalys | boolean | no | |
kassaflodesanalys_omission_confirmed | boolean | no |
Response fields
| Name | Type |
|---|---|
narrative_id | string |
fiscal_period_id | string |
description | string | null |
important_events | string | null |
resultatdisposition | string | null |
proposed_dividend | number | null |
agm_date | string | null |
long_term_debt_over_five_years | number | null |
securities_pledged | string | null |
contingent_liabilities | string | null |
parent_company_name | string | null |
parent_company_org_number | string | null |
parent_company_city | string | null |
medelantal_anstallda_override | number | null |
agm_disposition_outcome | "proposal_approved" | "alternative_decision" | null |
agm_disposition_decision | string | null |
note_overrides | object |
omit_kassaflodesanalys | boolean |
updated_at | string |
Example request
{
"description": "Bolaget bedriver konsultverksamhet inom IT.",
"agm_date": "2027-05-20"
}
Example response
{
"data": {
"narrative_id": "1f0e…",
"fiscal_period_id": "7c2b…",
"description": "Bolaget bedriver konsultverksamhet inom IT.",
"agm_date": "2027-05-20",
"updated_at": "2027-03-02T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures
arsredovisning.add-signatory · scope bookkeeping:write
Add a board member or the VD to the årsredovisning signer roster.
Adds a pending signer slot (role and name) to the roster for the räkenskapsår. ÅRL 2 kap. 7 § requires every ordinarie styrelseledamot and the VD, if any, to sign. This records who is to sign; it signs nothing and involves no BankID. Any roster change clears the signer roster confirmation. Answers 201 with the slot. Idempotent. Dry-runnable.
Use when: Setting up who signs, before finalizing a version (POST .../arsredovisning/versions action finalize).
Don't use for: Recording that someone signed (PATCH .../signatures/{signatureId}) or filing with Bolagsverket.
Pitfalls
- The same role and name twice on the unbound roster answers 409 ARSREDOVISNING_SIGNER_ALREADY_EXISTS.
- signer_name is the name as registered at Bolagsverket; a personnummer is refused (400).
- Confirm the roster afterwards: PATCH .../compliance {"signer_roster_confirmed": true}.
Risk: medium · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
role | "Styrelseledamot" | "Styrelseordförande" | "VD" | "Verkställande direktör" | yes | Styrelseledamot, Styrelseordförande, VD or Verkställande direktör. |
signer_name | string | yes | Full name as registered at Bolagsverket. Never a personnummer. |
Response fields
| Name | Type | Description |
|---|---|---|
signature_id | string | |
fiscal_period_id | string | |
annual_report_version_id | string | null | Null while the slot is on the unbound roster. |
role | string | |
signer_name | string | |
status | "pending" | "signed" | "declined" | |
signed_at | string | null | |
signing_method | "paper_original" | "advanced_e_signature" | "bankid" | "bolagsverket" | null | |
evidence_reference | string | null | |
evidence_recorded_at | string | null | |
created_at | string |
Example request
{
"role": "Styrelseledamot",
"signer_name": "Anna Andersson"
}
Example response
{
"data": {
"signature_id": "5b1c…",
"fiscal_period_id": "7c2b…",
"annual_report_version_id": null,
"role": "Styrelseledamot",
"signer_name": "Anna Andersson",
"status": "pending",
"signed_at": null,
"signing_method": null,
"evidence_reference": null,
"evidence_recorded_at": null,
"created_at": "2027-03-02T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/versions
arsredovisning.create-version · scope bookkeeping:write
Freeze an immutable årsredovisning version: a draft snapshot, or the version that gets signed.
Builds the årsredovisning from a complete read of the books (refused while an SIE import is unfinished) and stores it as an immutable version with its content hash. action snapshot stores a draft; action finalize requires every signing-stage check to pass, marks the version ready_for_signature, supersedes an earlier ready or signed version and binds the signer roster to it. certificate_signer names who signs the fastställelseintyg. expected_content_hash (from a dry run) makes the call refuse when the content has changed since. Answers 201 with the version. Idempotent. Dry-runnable: the dry run answers the content hash and the validation counts.
Use when: The texts, compliance answers and signer roster are done and the document is to be signed (finalize), or a checkpoint of the draft is wanted (snapshot).
Don't use for: Filing with Bolagsverket (dashboard only, BankID), recording signatures (PATCH .../signatures/{signatureId}) or reading the document (GET .../arsredovisning/pdf).
Pitfalls
- Statements that do not tie, or (finalize) any signing-stage error, answer 409 ARSREDOVISNING_INCOMPLETE with the validation in details: run gnubok_validate_arsredovisning with stage signing first.
- finalize needs a confirmed signer roster (PATCH .../compliance {"signer_roster_confirmed": true}) and at least one signer.
- Content changed since the hash you pass: 409 ARSREDOVISNING_CONTENT_CHANGED; dry-run again and review.
- A new finalize supersedes the previous ready_for_signature version; signatures recorded on it do not carry over.
- Refused while an SIE import is unfinished: complete or undo it first.
Risk: high · Idempotent: yes · Reversible: no · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
action | "snapshot" | "finalize" | yes | snapshot saves a draft version; finalize freezes the version for signing (ready_for_signature). |
certificate_signer | object | no | Who signs the fastställelseintyg (a board member or the VD). |
expected_content_hash | string | no | The content_hash a dry run answered; the version is refused when the content no longer matches. |
Response fields
| Name | Type | Description |
|---|---|---|
annual_report_version_id | string | |
version_number | number | |
status | "draft" | "ready_for_signature" | "signed" | "filed" | "registered" | "superseded" | |
framework | string | |
content_hash | string | SHA-256 of the frozen content (signature dates excluded). |
taxonomy_version | string | null | |
entry_point | string | null | |
finalized_at | string | null | |
created_at | string |
Example request
{
"action": "finalize",
"certificate_signer": {
"first_name": "Anna",
"last_name": "Andersson",
"role": "Styrelseledamot"
}
}
Example response
{
"data": {
"annual_report_version_id": "4e7d…",
"version_number": 2,
"status": "ready_for_signature",
"framework": "k2",
"content_hash": "9f86d081…",
"taxonomy_version": "2024-09-12",
"entry_point": "k2-ab-risbs-2024-09-12",
"finalized_at": "2027-03-02T09:00:00Z",
"created_at": "2027-03-02T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/close
fiscal-periods.close · scope bookkeeping:write
Close a fiscal period (IRREVERSIBLE per BFL 5 kap 8 §).
Sets is_closed=true + closed_at on the period. Pre-requisites: period must be locked (call /lock first) AND year-end closing must have been executed (call /year-end first). Sync. The DB blocks any subsequent JE inserts.
Use when: Final step in the year-end flow: lock → year-end → close. Closing freezes the period for BFL 7 kap retention.
Don't use for: Locking a period (use /lock). Running the year-end closing entry (use /year-end). UNDOING a close (not supported, irreversible).
Pitfalls
- Idempotency-Key is mandatory.
- IRREVERSIBLE. Once is_closed=true, the period is read-only forever (BFL 5 kap 8 § + 7 kap).
- Pre-conditions: locked + closing_entry_id present. Otherwise the call returns CONFLICT.
Risk: high · Idempotent: yes · Reversible: no · Dry-run supported: no
Response fields
| Name | Type |
|---|---|
id | string |
is_closed | true |
closed_at | string |
Example response
{
"data": {
"id": "a8f1…",
"is_closed": true,
"closed_at": "2026-05-12T14:30:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/close-external
fiscal-periods.close-external · scope bookkeeping:write
Mark a migrated fiscal year as closed in the previous system (klarmarkera).
Closes and locks an imported historical räkenskapsår whose bokslut was done in the previous bookkeeping software, without a closing entry here, and writes the decision to the audit log. Only for migrated years: the year must have ended, have no closing entry in Accounted, and hold imported verifikat, no verifikat, or balance-sheet-only verifikat with the next year's IB already posted. Unbooked bank transactions in the year block it, as for a lock. Undo with reopen-external. Idempotent. Dry-runnable.
Use when: After an SIE migration, the earlier years show as pending bokslut although their bokslut was done in the old system.
Don't use for: Closing a year bookkept in Accounted: run the year-end (POST /fiscal-periods/{id}/year-end), which transfers the result and carries the balances forward.
Pitfalls
- A year bookkept here with result accounts answers 409 FISCAL_PERIOD_CLOSE_EXTERNAL_NATIVE_BOOKKEEPING: run the year-end instead.
- A running year answers 409 FISCAL_PERIOD_CLOSE_EXTERNAL_NOT_ENDED.
- Unbooked bank transactions answer 400 PERIOD_HAS_UNBOOKED_TRANSACTIONS with the count in details.reason.
Risk: high · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Response fields
| Name | Type |
|---|---|
id | string |
name | string |
period_start | string |
period_end | string |
is_closed | boolean |
closed_at | string | null |
closed_externally | boolean |
locked_at | string | null |
previous_period_id | string | null |
created_at | string |
Example response
{
"data": {
"id": "a8f1…",
"name": "Räkenskapsår 2024",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"is_closed": true,
"closed_at": "2026-09-25T09:00:00Z",
"closed_externally": true,
"locked_at": "2026-09-25T09:00:00Z",
"previous_period_id": "5c2e…",
"created_at": "2026-12-01T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/currency-revaluation
fiscal-periods.currency-revaluation · scope bookkeeping:write
Run FX revaluation for the fiscal period.
Re-rates open foreign-currency AR (1510) and AP (2440) at the closing date's Riksbanken rate and posts the SEK delta to 3960 (valutakursvinst) / 7960 (valutakursförlust). Returns 202 with operation_id. Idempotent per-period: the engine throws if a revaluation has already been posted for the same fiscal_period_id.
Use when: Before /year-end if your books have open foreign-currency receivables or payables. /year-end also runs this internally, so you only need to call it separately when you want the FX-only entry without the full closing.
Don't use for: Re-running on the same period (CURRENCY_REVALUATION_ALREADY_EXISTS). Revaluing a closed period (the trigger blocks JE writes to closed periods).
Pitfalls
- Idempotency-Key is mandatory.
- Engine returns null if no open foreign-currency items exist: the operation succeeds with result.revaluation_entry_id=null.
- as_of_date defaults to period_end if omitted.
Risk: high · Idempotent: yes · Reversible: yes · Dry-run supported: no
Request body
| Name | Type | Required |
|---|---|---|
as_of_date | string | no |
Response fields
| Name | Type |
|---|---|
operation_id | string |
type | "fiscal_periods.currency_revaluation" |
status | "queued" | "running" | "succeeded" | "failed" |
poll_url | string |
webhook_event | "operation.completed" |
Example request
{
"as_of_date": "2026-12-31"
}
Example response
{
"data": {
"operation_id": "0e9c…",
"type": "fiscal_periods.currency_revaluation",
"status": "succeeded",
"poll_url": "/api/v1/operations/0e9c…",
"webhook_event": "operation.completed"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/lock
fiscal-periods.lock · scope bookkeeping:write
Lock a fiscal period (no new entries can be posted into it).
Sets locked_at on the period. Refuses if uncategorised business transactions remain in the period: they must be bokfört first. The DB trigger blocks JE inserts into locked periods; locking is the application-level pre-step before /close. Sync.
Use when: Finishing a period and you want to stop new postings. Step 1 of a three-step year-end flow: lock → year-end → close.
Don't use for: Locking an already-closed period (no-op). Bypassing the uncategorised-transactions guard: categorise or mark-private first.
Pitfalls
- Idempotency-Key is mandatory.
- A period with uncategorised business transactions cannot be locked; the response surfaces the count.
- Locking is reversible until /close: POST /fiscal-periods/{id}/unlock lifts it.
Risk: high · Idempotent: yes · Reversible: yes · Dry-run supported: no
Response fields
| Name | Type |
|---|---|
id | string |
locked_at | string |
is_closed | boolean |
Example response
{
"data": {
"id": "a8f1…",
"locked_at": "2026-05-12T14:00:00Z",
"is_closed": false
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/opening-balances
fiscal-periods.opening-balances · scope bookkeeping:write
Generate opening-balance verifikation for the next fiscal period.
Reads the closed period's trial balance, filters to BAS class 1-2 accounts with non-zero closing balance, and posts an opening verifikation (status=posted) onto the next_period_id. Sync. The path id is the CLOSED period; body.next_period_id is the target.
Use when: After /year-end + /close on a period, generate the IB into the next period so the new year starts with the correct balance sheet.
Don't use for: Posting opening balances on a manually-edited basis (use POST /journal-entries with source_type=manual). Re-running on the same target period (will produce duplicate IB entries).
Pitfalls
- Idempotency-Key is mandatory.
- next_period_id must reference the SAME company and must NOT already have an IB entry. The engine throws if it does.
- Only class 1 (assets) and 2 (equity/liabilities) flow into the IB; class 3-8 are zeroed by the closing entry.
Risk: high · Idempotent: yes · Reversible: yes · Dry-run supported: no
Request body
| Name | Type | Required |
|---|---|---|
next_period_id | string | yes |
Response fields
| Name | Type |
|---|---|
opening_entry_id | string |
voucher_series | string |
voucher_number | number |
next_period_id | string |
Example request
{
"next_period_id": "7b3a…"
}
Example response
{
"data": {
"opening_entry_id": "4d2a…",
"voucher_series": "A",
"voucher_number": 1,
"next_period_id": "7b3a…"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/opening-balances/correct
opening-balances.correct · scope bookkeeping:write
Correct a year's ingående balanser by storno: the full corrected IB replaces the old one.
Books the corrected IB verifikat from the lines given (the complete IB, not a difference), stornoes the old IB verifikat and relinks the year to the new one (BFL 5 kap 5 §: nothing posted is edited). The new verifikat's text references the one it corrects. With cascade=true the per-account change is also carried into every later year's IB; years that are closed, locked, behind the lock date or have a bokslut are skipped and reported. Only for an open, unlocked year with an IB and no bokslut. Idempotent. Dry-runnable: the dry run previews the new verifikat and the per-account change and writes nothing.
Use when: The IB booked for a year was wrong (a typo, a balance the previous system corrected later).
Don't use for: A year without an IB (POST /fiscal-periods/{id}/opening-balances/manual), a single wrong line in an open year (POST /journal-entries/{id}/strike-lines on the IB verifikat corrects inside the same verifikat), or a year that is locked, closed or has a bokslut (unwind those first).
Pitfalls
- Send the COMPLETE corrected IB: accounts left out end at zero.
- A year without an IB answers 409 OB_CORRECT_NO_EXISTING; one with a posted bokslut 409 OB_CORRECT_YEAR_END_EXISTS.
- A company lock date on or after the year's start answers 409 OB_COMPANY_LOCK_DATE.
- If the storno or relink fails the new IB is stornoed again and 500 OB_CORRECT_FAILED names both entry ids: the year keeps its old IB.
- cascade is best effort per later year: read cascade.skipped in the response and correct those years by hand.
Risk: high · Idempotent: yes · Reversible: no · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
lines | object[] | yes | The IB per account. Zero rows are dropped; debit must equal credit. |
cascade | boolean | no | Also carry the per-account change into every later year's IB. Default false. |
Response fields
| Name | Type | Description |
|---|---|---|
journal_entry_id | string | |
voucher_series | string | null | |
voucher_number | number | null | |
reversed_entry_id | string | The old IB verifikat, now stornoed. |
fiscal_period_id | string | |
lines_created | number | |
total_debit | number | |
total_credit | number | |
cascade | object (optional) |
Example request
{
"lines": [
{
"account_number": "1930",
"amount": 84250.5
},
{
"account_number": "1510",
"debit_amount": 12500,
"credit_amount": 0
},
{
"account_number": "2440",
"amount": -9800
},
{
"account_number": "2081",
"amount": -25000
},
{
"account_number": "2099",
"amount": -61950.5
}
],
"cascade": true
}
Example response
{
"data": {
"journal_entry_id": "8c1e…",
"voucher_series": "A",
"voucher_number": 42,
"reversed_entry_id": "4d2a…",
"fiscal_period_id": "7b3a…",
"lines_created": 5,
"total_debit": 96750.5,
"total_credit": 96750.5,
"cascade": {
"corrected": [],
"skipped": []
}
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/opening-balances/manual
opening-balances.set-manual · scope bookkeeping:write
Book a fiscal year's ingående balanser (IB) from explicit lines, for a company new to Accounted.
Posts the IB verifikat (source_type opening_balance, series A, dated the year's first day) through the bookkeeping engine and links it to the year, as the dashboard's opening balance import does. Lines are balance sheet accounts only (class 1-2), zero rows dropped, at least two left, debit equal to credit. BAS accounts missing from the chart are activated. Refused when the year already has an IB, is closed or locked, or starts on or before the company lock date. Idempotent. Dry-runnable: the dry run previews the verifikat and writes nothing.
Use when: The company moved from another system without an SIE file and its first year in Accounted needs the balances from the previous system's balansräkning.
Don't use for: Carrying the IB forward from a year closed in Accounted (POST /fiscal-periods/{id}/opening-balances, or the year-end which does it), an SIE migration (POST /imports/sie brings its own IB), or changing an IB already booked (POST /fiscal-periods/{id}/opening-balances/correct).
Pitfalls
- A year that already has an IB answers 409 OB_PERIOD_ALREADY_HAS_BALANCES with details.existingEntryId: correct it instead.
- Class 3-8 accounts answer 400 OB_PNL_ACCOUNT, class 0 and 9 400 OB_NON_BALANCE_SHEET_ACCOUNT: an IB holds balance sheet accounts only, earlier years' results sit in equity (20xx).
- Debit and credit must match to the öre: 400 OB_UNBALANCED with details.diff.
- A company lock date on or after the year's start answers 409 OB_SET_COMPANY_LOCK_DATE; a closed or locked year 400 OB_PERIOD_CLOSED or OB_PERIOD_LOCKED.
- The IB is a posted verifikat: it is never edited or deleted, only corrected by storno through /opening-balances/correct.
Risk: high · Idempotent: yes · Reversible: no · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
lines | object[] | yes | The IB per account. Zero rows are dropped; debit must equal credit. |
Response fields
| Name | Type |
|---|---|
journal_entry_id | string |
voucher_series | string | null |
voucher_number | number | null |
fiscal_period_id | string |
entry_date | string |
lines_created | number |
total_debit | number |
total_credit | number |
Example request
{
"lines": [
{
"account_number": "1930",
"amount": 84250.5
},
{
"account_number": "1510",
"debit_amount": 12500,
"credit_amount": 0
},
{
"account_number": "2440",
"amount": -9800
},
{
"account_number": "2081",
"amount": -25000
},
{
"account_number": "2099",
"amount": -61950.5
}
]
}
Example response
{
"data": {
"journal_entry_id": "4d2a…",
"voucher_series": "A",
"voucher_number": 1,
"fiscal_period_id": "7b3a…",
"entry_date": "2026-01-01",
"lines_created": 5,
"total_debit": 96750.5,
"total_credit": 96750.5
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/reopen-external
fiscal-periods.reopen-external · scope bookkeeping:write
Undo klarmarkera: reopen a year marked closed in the previous system.
Reopens and unlocks a räkenskapsår that close-external closed, and writes the decision to the audit log. Only while that close is still the klarmarkera one: a year closed by a year-end run in Accounted is never reopened. Typical need: the prior-year SIE file was wrong and must be replaced. Idempotent. Dry-runnable.
Use when: A year was marked closed in the previous system by mistake, or its imported contents must be replaced.
Don't use for: Reopening a year closed by a year-end here (not possible), or unlocking a locked year (POST /fiscal-periods/{id}/unlock).
Pitfalls
- An open year answers 409 PERIOD_REOPEN_NOT_CLOSED.
- A year closed by a year-end run here answers 409 PERIOD_REOPEN_NOT_EXTERNAL.
- The lock is cleared too: lock or klarmarkera the year again once the correction is done.
Risk: high · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Response fields
| Name | Type |
|---|---|
id | string |
name | string |
period_start | string |
period_end | string |
is_closed | boolean |
closed_at | string | null |
closed_externally | boolean |
locked_at | string | null |
previous_period_id | string | null |
created_at | string |
Example response
{
"data": {
"id": "a8f1…",
"name": "Räkenskapsår 2024",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"is_closed": false,
"closed_at": null,
"closed_externally": false,
"locked_at": null,
"previous_period_id": "5c2e…",
"created_at": "2026-12-01T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/unlock
fiscal-periods.unlock · scope bookkeeping:write
Unlock a locked (not closed) fiscal year.
Clears locked_at so the year accepts postings again, and writes the unlock to the audit log (BFNAR 2013:2 behandlingshistorik). A closed year is never unlocked: past a close, corrections go into an open year as storno. Re-lock with POST /fiscal-periods/{id}/lock after the correction. Idempotent. Dry-runnable.
Use when: The user asked to correct something in a locked year, or a year-end must run on a year that was locked beforehand.
Don't use for: Getting a booking past a lock without the user asking for that correction, or reopening a closed year (a year marked closed in a previous system: POST /fiscal-periods/{id}/reopen-external).
Pitfalls
- A closed year answers 409 PERIOD_UNLOCK_CLOSED; an unlocked one 409 PERIOD_UNLOCK_NOT_LOCKED.
- The company-wide lock date (bookkeeping_locked_through) is a separate lock this does not touch.
Risk: high · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Response fields
| Name | Type |
|---|---|
id | string |
name | string |
period_start | string |
period_end | string |
is_closed | boolean |
closed_at | string | null |
closed_externally | boolean |
locked_at | string | null |
previous_period_id | string | null |
created_at | string |
Example response
{
"data": {
"id": "a8f1…",
"name": "Räkenskapsår 2027",
"period_start": "2027-01-01",
"period_end": "2027-12-31",
"is_closed": false,
"closed_at": null,
"closed_externally": false,
"locked_at": null,
"previous_period_id": "5c2e…",
"created_at": "2026-12-01T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/fiscal-periods/:id/year-end
fiscal-periods.year-end · scope bookkeeping:write
Execute year-end closing (currency revaluation + closing entry).
Async-operation endpoint. Runs the year-end closing flow: currency revaluation (FX gains/losses to 3960/7960), then posts the closing entry that zeroes class 3-8 onto årets resultat (2099 for AB, the relevant eget-kapital account in the 2010-2019 range for enskild firma: the engine resolves which based on company.entity_type). Returns 202 with operation_id; subscribe to operation.completed or poll /v1/operations/{id}.
Use when: After /lock and a passing /compliance/check?type=year_end_readiness, you want to run the closing entry. This is step 2 of the lock → year-end → close flow.
Don't use for: Re-running year-end (per-period idempotent: fails if closing_entry_id is already set). Closing the period (use /close after year-end succeeds).
Pitfalls
- Idempotency-Key is mandatory.
- Period must pass year_end_readiness checks (no drafts, no unexplained voucher gaps, trial balance balanced). The engine re-validates and aborts if not.
- Closing entry is itself a verifikation (posted): the period must NOT already be closed.
Risk: high · Idempotent: yes · Reversible: no · Dry-run supported: no
Response fields
| Name | Type |
|---|---|
operation_id | string |
type | "fiscal_periods.year_end" |
status | "queued" | "running" | "succeeded" | "failed" |
poll_url | string |
webhook_event | "operation.completed" |
Example response
{
"data": {
"operation_id": "0e9c…",
"type": "fiscal_periods.year_end",
"status": "succeeded",
"poll_url": "/api/v1/operations/0e9c…",
"webhook_event": "operation.completed"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
PATCH /api/v1/companies/:companyId/fiscal-periods/:id
fiscal-periods.update · scope bookkeeping:write
Rename or re-date an open fiscal year.
Sparse update of an open, unlocked räkenskapsår: name, period_start, period_end. The name can change at any time on an open year; the dates only while no posted or reversed verifikat exist in it. New dates follow the same BFL 3 kap. rules as create (18-month cap, month-end end, 1st-of-month start unless it is the earliest year, calendar year for an enskild firma) and may not overlap another year. Idempotent. Dry-runnable.
Use when: A year was created with the wrong dates or name and nothing has been booked in it yet.
Don't use for: Moving verifikat between years, changing a locked or closed year, or lengthening a year that already has bookings.
Pitfalls
- Any posted or reversed verifikat in the year answers 409 FISCAL_PERIOD_HAS_POSTED_ENTRIES when dates are sent: send only name to rename.
- A locked year answers 409 FISCAL_PERIOD_UPDATE_LOCKED, a closed one 409 FISCAL_PERIOD_UPDATE_CLOSED.
- Re-dating does not re-chain previous_period_id: keep the years contiguous yourself.
Risk: medium · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required |
|---|---|---|
name | string | no |
period_start | string | no |
period_end | string | no |
Response fields
| Name | Type |
|---|---|
id | string |
name | string |
period_start | string |
period_end | string |
is_closed | boolean |
closed_at | string | null |
closed_externally | boolean |
locked_at | string | null |
previous_period_id | string | null |
created_at | string |
Example request
{
"period_end": "2027-06-30"
}
Example response
{
"data": {
"id": "a8f1…",
"name": "Räkenskapsår 2027",
"period_start": "2027-01-01",
"period_end": "2027-06-30",
"is_closed": false,
"closed_at": null,
"closed_externally": false,
"locked_at": null,
"previous_period_id": "5c2e…",
"created_at": "2026-12-01T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
PATCH /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/compliance
arsredovisning.update-compliance · scope bookkeeping:write
Answer the årsredovisning compliance questions and record the confirmations.
Sparse update of the compliance profile the ÅRL, K2 and K3 checks read: publikt bolag, likvidation, listed securities, moderföretag and group size, foreign branch, crypto, share-based payments, convertibles, building revenue share, deferred tax, reporting currency, revisionsberättelse, dividend prudence. narrative_confirmed, k2_assessment_confirmed and signer_roster_confirmed record (true) or withdraw (false) the user's confirmations with a timestamp. Answers the recomputed eligibility, validation and capabilities. Idempotent. Dry-runnable.
Use when: The validation (gnubok_validate_arsredovisning) reports an unanswered compliance question or a missing confirmation.
Don't use for: The document texts (POST .../arsredovisning/narrative) or the signer roster itself (POST .../arsredovisning/signatures).
Pitfalls
- An unanswered question is null, never false: false is a legal assertion that the condition does not apply.
- signer_roster_confirmed asserts the roster matches the board and VD registered at Bolagsverket; any later roster change clears it.
- is_parent_company false also clears parent_group_size and prepares_consolidated_accounts.
- Send at least one field (400 VALIDATION_ERROR otherwise).
Risk: medium · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
is_public_limited_company | boolean | null | no | |
is_in_liquidation | boolean | null | no | |
securities_traded_on_regulated_market | boolean | null | no | |
is_parent_company | boolean | null | no | |
parent_group_size | "none" | "small" | "large" | null | no | |
prepares_consolidated_accounts | boolean | null | no | |
has_foreign_branch | boolean | null | no | |
has_crypto_assets | boolean | null | no | |
has_share_based_payments | boolean | null | no | |
has_convertible_debt | boolean | null | no | |
building_revenue_share_pct | number | null | no | |
has_material_deferred_tax | boolean | null | no | |
reporting_currency | "SEK" | "EUR" | no | |
auditor_report_required | boolean | null | no | |
auditor_report_included | boolean | no | |
dividend_prudence_confirmed | boolean | null | no | |
narrative_confirmed | boolean | no | The user has reviewed the förvaltningsberättelse texts. |
k2_assessment_confirmed | boolean | no | The user confirms the K2 eligibility assessment. |
signer_roster_confirmed | boolean | no | The user confirms the signer roster matches the board and VD registered at Bolagsverket. |
Response fields
| Name | Type | Description |
|---|---|---|
profile | object | The compliance profile answers and confirmation timestamps (annual_report_profile_id, not id). |
disclosures | object | |
eligibility | object | K2 eligibility, size classification and digital filing eligibility. |
validation | object | Draft-stage validation: ok, error_count, warning_count, issues. |
capabilities | object | |
report_summary | object |
Example request
{
"is_public_limited_company": false,
"k2_assessment_confirmed": true
}
Example response
{
"data": {
"profile": {
"annual_report_profile_id": "9d3a…",
"is_public_limited_company": false
},
"validation": {
"stage": "draft",
"ok": true,
"error_count": 0,
"warning_count": 1,
"issues": []
},
"report_summary": {
"proposed_dividend": 0,
"distributable_equity": 412000
}
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
PATCH /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures/:signatureId
arsredovisning.record-signature · scope bookkeeping:write
Record that a signer signed the frozen årsredovisning version, or declined.
status signed records the evidence of a signature made outside the product (a paper original or an advanced e-signature): the ready_for_signature version it is for, the method, where the original is kept (evidence_reference) and the signing time. status declined marks the slot declined. Only a pending slot of this period transitions, once. ÅRL requires each signer to date their signature; the date must fall between the version's finalization and today. Idempotent. Dry-runnable.
Use when: The board has signed the printed or e-signed document and the signatures are to be registered.
Don't use for: Adding signers (POST .../signatures), filing with Bolagsverket, or BankID signing (not available here).
Pitfalls
- A version that is not ready_for_signature answers 409 ARSREDOVISNING_VERSION_NOT_SIGNABLE.
- A slot already signed or declined, bound to another version, or of another period answers 409 SIGNATURE_INVALID_TRANSITION.
- A signed_at before finalization or in the future answers 400 ARSREDOVISNING_SIGNATURE_DATE_INVALID.
- evidence_reference is archive:<ref>, document:<id> or receipt:<ref>, not free text.
- Recorded signatures cannot be undone: finalize a new version instead.
Risk: medium · Idempotent: yes · Reversible: no · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
status | "signed" | "declined" | yes | |
annual_report_version_id | string | no | Required for signed: the ready_for_signature version. |
signing_method | "paper_original" | "advanced_e_signature" | "bankid" | no | Required for signed. |
evidence_reference | string | no | Required for signed: archive:<ref>, document:<id> or receipt:<ref>. |
signed_at | string | no | signed only: ISO timestamp, defaults to now. |
Response fields
| Name | Type | Description |
|---|---|---|
signature_id | string | |
fiscal_period_id | string | |
annual_report_version_id | string | null | Null while the slot is on the unbound roster. |
role | string | |
signer_name | string | |
status | "pending" | "signed" | "declined" | |
signed_at | string | null | |
signing_method | "paper_original" | "advanced_e_signature" | "bankid" | "bolagsverket" | null | |
evidence_reference | string | null | |
evidence_recorded_at | string | null | |
created_at | string |
Example request
{
"status": "signed",
"annual_report_version_id": "4e7d…",
"signing_method": "paper_original",
"evidence_reference": "archive:AR-2026-1",
"signed_at": "2027-03-05T10:00:00Z"
}
Example response
{
"data": {
"signature_id": "5b1c…",
"fiscal_period_id": "7c2b…",
"annual_report_version_id": "4e7d…",
"role": "Styrelseledamot",
"signer_name": "Anna Andersson",
"status": "signed",
"signed_at": "2027-03-05T10:00:00Z",
"signing_method": "paper_original",
"evidence_reference": "archive:AR-2026-1",
"evidence_recorded_at": null,
"created_at": "2027-03-02T09:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
DELETE /api/v1/companies/:companyId/fiscal-periods/:id/arsredovisning/signatures/:signatureId
arsredovisning.remove-signatory · scope bookkeeping:write
Remove a signer from the årsredovisning roster before a version binds it.
Deletes a pending signer slot that no version has bound yet. Slots bound to a finalized version stay (they are part of what gets signed): finalize a new version with the corrected roster instead. Any roster change clears the signer roster confirmation. Idempotent. Dry-runnable.
Use when: A signer was added by mistake or has left the board before the version is finalized.
Don't use for: Declining a bound slot (PATCH .../signatures/{signatureId} {"status": "declined"}).
Pitfalls
- A bound, signed or declined slot answers 409 ARSREDOVISNING_SIGNER_ROSTER_LOCKED.
- Takes no body.
Risk: low · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
dry_run | string | no | true (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits. |
Response fields
| Name | Type |
|---|---|
signature_id | string |
deleted | true |
Example response
{
"data": {
"signature_id": "5b1c…",
"deleted": true
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}