Dimensions
Cost-centre / project dimensions and their values for tagging journal lines.
Endpoints
GET/api/v1/companies/:companyId/dimensions: List dimensions (kostnadsställe/projekt) with their values.POST/api/v1/companies/:companyId/dimensions/:id/values: Create a dimension value (kostnadsställe/projekt code).PATCH/api/v1/companies/:companyId/dimensions/:id/values/:valueId: Update a dimension value (rename, archive, set start/end date).DELETE/api/v1/companies/:companyId/dimensions/:id/values/:valueId: Delete an unreferenced dimension value.
GET /api/v1/companies/:companyId/dimensions
dimensions.list · scope reports:read
List dimensions (kostnadsställe/projekt) with their values.
Returns the company's dimension registry: SIE #DIM entries keyed by sie_dim_no (1 = Kostnadsställe, 6 = Projekt; both always exist): with the registered values (#OBJEKT) nested under each dimension. Dimensions are ordered by sort_order, values by code. Line-level tags on journal entries reference these values as {"<sie_dim_no>":"<code>"} in the dimensions map.
Use when: You need the valid dimension value codes before tagging journal-entry lines with a cost centre or project, or you are rendering a dimension picker.
Don't use for: Filtering reports (pass the dimension filter to the report endpoints once available) or reading which lines carry a tag (read the journal entries themselves).
Pitfalls
- Dimension value codes are STRINGS and case-sensitive: "P001", not 1.
- sie_dim_no is the key used in journal_entry_lines.dimensions, NOT the dimension row id.
- is_active=false values are historical (archived): do not tag new lines with them.
- resets_annually=true (dim 1) means balances reset each fiscal year; dim 6 (projekt) accumulates across years.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Example response
{
"data": {
"dimensions": [
{
"id": "0e9c…",
"sie_dim_no": 1,
"name": "Kostnadsställe",
"resets_annually": true,
"is_system": true,
"is_active": true,
"sort_order": 10,
"values": [
{
"id": "a8f1…",
"code": "BUTIK",
"name": "Butiken",
"is_active": true,
"start_date": null,
"end_date": null
}
]
}
]
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/dimensions/:id/values
dimensions.values.create · scope bookkeeping:write
Create a dimension value (kostnadsställe/projekt code).
Registers a new value (SIE #OBJEKT) under a dimension: e.g. a new project code under dimension 6. Requires Idempotency-Key (UUID). Supports ?dry_run=true to validate the code format without committing. The :id path segment is the dimension row id (from GET …/dimensions), not the sie_dim_no. Duplicate codes within the dimension return 409 DIMENSION_VALUE_DUPLICATE_CODE.
Use when: A voucher or invoice references a cost centre / project code that does not exist yet and the user has confirmed it should be created.
Don't use for: Renaming or archiving an existing value (dashboard register in v1). Tagging lines: pass the dimensions map on the journal-entry line instead.
Pitfalls
- Idempotency-Key is mandatory: calls without it return 400 VALIDATION_ERROR.
- The :id segment is the dimension UUID, not the SIE dimension number.
- Codes are limited to the strict Fortnox charset (A-Ö, digits, _, +, -; max 20 chars) even though historical imported codes may be looser.
- code is immutable after creation: there is no rename in v1; create the correct code and archive the wrong one.
Risk: low · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Example request
{
"code": "P001",
"name": "Villa Almgren tak"
}
Example response
{
"data": {
"id": "0e9c…",
"dimension_id": "a8f1…",
"code": "P001",
"name": "Villa Almgren tak",
"is_active": true,
"start_date": null,
"end_date": null,
"created_at": "2026-07-02T12:00:00Z"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
PATCH /api/v1/companies/:companyId/dimensions/:id/values/:valueId
dimensions.values.update · scope bookkeeping:write
Update a dimension value (rename, archive, set start/end date).
Sparse update of a dimension value (SIE #OBJEKT): name, is_active (false = archive), start_date, end_date. code is immutable: renaming a code would orphan every journal line tagged with it; create a new value and archive the old one instead. Dates are only allowed on accumulating dimensions (resets_annually=false, e.g. dim 6 Projekt): use end_date to close a finished project. Idempotent (mandatory Idempotency-Key) and dry-runnable.
Use when: You need to rename a project/cost-centre, mark a finished project with an end date, or archive (is_active=false) a value that should no longer be used on new lines.
Don't use for: Changing the code (immutable: create + archive instead). Removing an unused value entirely (use DELETE). Tagging lines (pass dimensions on the journal-entry line or invoice).
Pitfalls
- Idempotency-Key is mandatory.
- The :id segment is the dimension UUID and :valueId the value UUID (both from GET …/dimensions), not SIE numbers or codes.
- start_date/end_date return 400 DIMENSION_VALUE_DATES_NOT_ALLOWED on resets_annually dimensions (dim 1 Kostnadsställe).
- Archived values (is_active=false) still appear in GET …/dimensions and remain valid on historical lines; they are only blocked for NEW tags.
Risk: low · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Example request
{
"end_date": "2026-08-31",
"is_active": false
}
Example response
{
"data": {
"id": "0e9c…",
"dimension_id": "a8f1…",
"code": "P001",
"name": "Villa Almgren tak",
"is_active": false,
"start_date": null,
"end_date": "2026-08-31"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
DELETE /api/v1/companies/:companyId/dimensions/:id/values/:valueId
dimensions.values.delete · scope bookkeeping:write
Delete an unreferenced dimension value.
Hard-deletes a dimension value (SIE #OBJEKT) that no journal line references. Values used on posted or reversed verifikat are retained for the BFL 7-year archive and cannot be deleted: the DB trigger blocks it and this endpoint returns 409 DIMENSION_VALUE_REFERENCED. Archive those instead (PATCH is_active=false). Requires Idempotency-Key.
Use when: A project/cost-centre code was created by mistake (typo, duplicate) and has never been used on any booking.
Don't use for: Retiring a project that has bookings: PATCH is_active=false (and optionally end_date) instead. Deleting a whole dimension (not supported).
Pitfalls
- Idempotency-Key is mandatory.
- 409 DIMENSION_VALUE_REFERENCED means the value is used on booked verifikat: it can never be deleted, only archived.
- Deletion is permanent: the code can be re-created afterwards, but the old row id is gone.
Risk: medium · Idempotent: yes · Reversible: no · Dry-run supported: no
Example response
{
"data": {
"deleted": true,
"id": "0e9c…"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}