Menu

Fixed assets

The anläggningsregister: register an asset (no voucher, the purchase is already booked), correct it while no depreciation is posted, and dispose it, which posts the avyttring voucher with gain or loss, VAT and jämkning.

Endpoints


GET /api/v1/companies/:companyId/assets

assets.list · scope reports:read

List the fixed-asset register (anläggningsregister).

Returns every asset in the register with its category, acquisition basis, useful life, BAS account triple, disposal state and has_posted_depreciation. Pass ?active_only=true to leave out disposed assets.

Use when: You need the anläggningsregister: before proposing depreciation, to check which assets are still open, or to find the asset id for an update or disposal.

Don't use for: The bookkept balance on 12xx accounts (use the trial balance or balance sheet). Proposing or posting depreciation (fiscal-periods year-end flow).

Pitfalls

  • has_posted_depreciation=true locks acquisition_date, acquisition_cost and category: PATCH returns 409 ASSET_CORRECTION_BLOCKED and a correction goes through storno.
  • Disposed assets stay in the register with disposed_at set (BFL retention); filter with active_only=true when you want the open ones.
  • acquisition_cost is excl. VAT. The purchase voucher is not linked here: the register does not post anything on create.

Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no

Query parameters

NameTypeRequiredDescription
active_only"true" | "false"notrue returns only assets that have not been disposed. Default: the whole register.

Response fields

NameTypeDescription
assets[].namestring
assets[].category"immaterial" | "building" | "land_improvement" | "machinery" | "equipment" | "vehicle" | "computer" | "other_tangible"
assets[].acquisition_datestring
assets[].acquisition_costnumber
assets[].salvage_valuenumber
assets[].useful_life_monthsnumber
assets[].depreciation_methodstring
assets[].bas_asset_accountstring
assets[].bas_accumulated_accountstring
assets[].bas_expense_accountstring
assets[].k3_componentsobject[] | null
assets[].opening_accumulated_depreciationnumberAckumulerad avskrivning booked in a previous system before the asset entered Accounted; 0 when none. Never posted by Accounted.
assets[].opening_depreciation_datestring | null
assets[].notesstring | null
assets[].disposed_atstring | null
assets[].disposal_type"sale" | "scrap" | "business_transfer" | null
assets[].disposed_proceedsnumber | null
assets[].disposal_journal_entry_idstring | null
assets[].has_posted_depreciationbooleanTrue once any planenlig avskrivning has been posted: acquisition_date, acquisition_cost and category are then locked (ASSET_CORRECTION_BLOCKED) and a correction goes through storno.
assets[].deletablebooleanTrue while the row never reached the books (no posted depreciation, not disposed): DELETE /assets/{id} removes it. False means the row is räkenskapsinformation and leaves only through disposal or storno (409 ASSET_DELETE_BLOCKED).
assets[].created_atstring
assets[].updated_atstring
assets[].idstring

Example response

{
  "data": {
    "assets": [
      {
        "id": "0e9c…",
        "name": "MacBook Pro 16\"",
        "category": "computer",
        "acquisition_date": "2026-03-01",
        "acquisition_cost": 32000,
        "salvage_value": 0,
        "useful_life_months": 36,
        "depreciation_method": "linear",
        "bas_asset_account": "1224",
        "bas_accumulated_account": "1229",
        "bas_expense_account": "7832",
        "k3_components": null,
        "opening_accumulated_depreciation": 0,
        "opening_depreciation_date": null,
        "notes": null,
        "disposed_at": null,
        "disposal_type": null,
        "disposed_proceeds": null,
        "disposal_journal_entry_id": null,
        "has_posted_depreciation": false,
        "deletable": true,
        "created_at": "2026-03-01T09:12:00.000Z",
        "updated_at": "2026-03-01T09:12:00.000Z"
      }
    ]
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/assets/:id

assets.get · scope reports:read

Get one fixed asset.

Returns the asset with its acquisition basis, BAS account triple, K3 components, disposal state and has_posted_depreciation.

Use when: You have an asset id from the listing and need the full row before an update or disposal.

Don't use for: Listing the register (GET /assets). The depreciation schedule per period (year-end flow).

Pitfalls

  • Returns 404 ASSET_NOT_FOUND for an id in another company: assets are company-scoped.

Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no

Response fields

NameTypeDescription
namestring
category"immaterial" | "building" | "land_improvement" | "machinery" | "equipment" | "vehicle" | "computer" | "other_tangible"
acquisition_datestring
acquisition_costnumber
salvage_valuenumber
useful_life_monthsnumber
depreciation_methodstring
bas_asset_accountstring
bas_accumulated_accountstring
bas_expense_accountstring
k3_componentsobject[] | null
opening_accumulated_depreciationnumberAckumulerad avskrivning booked in a previous system before the asset entered Accounted; 0 when none. Never posted by Accounted.
opening_depreciation_datestring | null
notesstring | null
disposed_atstring | null
disposal_type"sale" | "scrap" | "business_transfer" | null
disposed_proceedsnumber | null
disposal_journal_entry_idstring | null
has_posted_depreciationbooleanTrue once any planenlig avskrivning has been posted: acquisition_date, acquisition_cost and category are then locked (ASSET_CORRECTION_BLOCKED) and a correction goes through storno.
deletablebooleanTrue while the row never reached the books (no posted depreciation, not disposed): DELETE /assets/{id} removes it. False means the row is räkenskapsinformation and leaves only through disposal or storno (409 ASSET_DELETE_BLOCKED).
created_atstring
updated_atstring
idstring

Example response

{
  "data": {
    "id": "0e9c…",
    "name": "MacBook Pro 16\"",
    "category": "computer",
    "acquisition_date": "2026-03-01",
    "acquisition_cost": 32000,
    "salvage_value": 0,
    "useful_life_months": 36,
    "depreciation_method": "linear",
    "bas_asset_account": "1224",
    "bas_accumulated_account": "1229",
    "bas_expense_account": "7832",
    "k3_components": null,
    "opening_accumulated_depreciation": 0,
    "opening_depreciation_date": null,
    "notes": "Serienummer C02XY…",
    "disposed_at": null,
    "disposal_type": null,
    "disposed_proceeds": null,
    "disposal_journal_entry_id": null,
    "has_posted_depreciation": false,
    "deletable": true,
    "created_at": "2026-03-01T09:12:00.000Z",
    "updated_at": "2026-03-02T08:00:00.000Z"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/assets

assets.create · scope bookkeeping:write

Register a fixed asset (no voucher is posted).

Adds an asset to the anläggningsregister. BAS accounts default per category (framework-aware for intangibles: a K2 company lands on 1090/1099). No journal entry is posted: the acquisition is already in the books via the bank payment or supplier invoice. Dry-runnable: returns the resolved accounts without writing.

Use when: A purchase over the förbrukningsinventarie threshold (half a prisbasbelopp) or with a useful life over three years has been booked and must be depreciated over time.

Don't use for: Booking the purchase itself (categorize the bank transaction or register the supplier invoice). Small or short-lived items: expense them on 54xx instead of capitalising.

Pitfalls

  • k3_components is accepted only when the company applies K3: 422 K3_REQUIRED_FOR_COMPONENTS otherwise. Components must sum to acquisition_cost.
  • opening_accumulated_depreciation must be between 0 and acquisition_cost - salvage_value. A positive amount requires opening_depreciation_date between acquisition_date and today (Europe/Stockholm). Zero clears the opening date.
  • Opening depreciation registers an amount already in the imported ledger and posts no voucher. Enter the amount for this asset from the previous asset register and manually reconcile the register totals with the imported ledger before depreciation or disposal; no automatic reconciliation is performed.
  • Opening fields lock after depreciation posted through Accounted's asset register or disposal. Manual ledger postings do not lock them.
  • A positive opening amount cannot be combined with non-empty k3_components. Opening balances for K3 component assets are unsupported; keep the component breakdown.
  • Account overrides must sit inside the category range (e.g. 1200-1299 for equipment) and may not be flagged Ej K2 for a K2 company (422 K2_EXCLUDED_ACCOUNT).
  • useful_life_months drives linear depreciation from acquisition_date, pro-rated in the first fiscal year.

Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: yes

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.

Request body

NameTypeRequiredDescription
namestringyesAsset name as it appears in the register.
category"immaterial" | "building" | "land_improvement" | "machinery" | "equipment" | "vehicle" | "computer" | "other_tangible"yesBAS category; drives the default account triple.
acquisition_datestringyesyyyy-MM-dd
acquisition_costnumberyesAcquisition cost excl. VAT, SEK.
salvage_valuenumbernoRestvärde at end of life, SEK. Default 0.
useful_life_monthsnumberyesNyttjandeperiod in months (60 = 5 years).
depreciation_method"linear"noOnly linear is writable; default linear.
restvarde_targetunknownno
bas_asset_accountstringnoOverride the anskaffningskonto (must be in the category range).
bas_accumulated_accountstringnoOverride the ackumulerade avskrivningar account.
bas_expense_accountstringnoOverride the avskrivningskostnad account.
k3_componentsobject[] | nullnoK3 component breakdown; K3 companies only. Components must sum to acquisition_cost.
opening_accumulated_depreciationnumbernoAccumulated depreciation for this asset from the previous asset register, SEK, 0 to acquisition_cost - salvage_value. No voucher or automatic reconciliation: manually reconcile register totals with the imported ledger before depreciation or disposal. Manual ledger postings do not lock opening edits; depreciation posted through Accounted's asset register or disposal does. The engine plans the remaining value over the remaining useful life. A positive amount cannot be combined with non-empty k3_components. Component opening balances are unsupported; keep the component breakdown.
opening_depreciation_datestring | nullnoyyyy-MM-dd the opening accumulated depreciation is stated per. Required when the amount is above 0; not after today, not before acquisition_date.
notesstringno

Response fields

NameTypeDescription
namestring
category"immaterial" | "building" | "land_improvement" | "machinery" | "equipment" | "vehicle" | "computer" | "other_tangible"
acquisition_datestring
acquisition_costnumber
salvage_valuenumber
useful_life_monthsnumber
depreciation_methodstring
bas_asset_accountstring
bas_accumulated_accountstring
bas_expense_accountstring
k3_componentsobject[] | null
opening_accumulated_depreciationnumberAckumulerad avskrivning booked in a previous system before the asset entered Accounted; 0 when none. Never posted by Accounted.
opening_depreciation_datestring | null
notesstring | null
disposed_atstring | null
disposal_type"sale" | "scrap" | "business_transfer" | null
disposed_proceedsnumber | null
disposal_journal_entry_idstring | null
has_posted_depreciationbooleanTrue once any planenlig avskrivning has been posted: acquisition_date, acquisition_cost and category are then locked (ASSET_CORRECTION_BLOCKED) and a correction goes through storno.
deletablebooleanTrue while the row never reached the books (no posted depreciation, not disposed): DELETE /assets/{id} removes it. False means the row is räkenskapsinformation and leaves only through disposal or storno (409 ASSET_DELETE_BLOCKED).
created_atstring
updated_atstring
idstring

Example request

{
  "name": "MacBook Pro 16\"",
  "category": "computer",
  "acquisition_date": "2026-03-01",
  "acquisition_cost": 32000,
  "useful_life_months": 36
}

Example response

{
  "data": {
    "id": "0e9c…",
    "name": "MacBook Pro 16\"",
    "category": "computer",
    "acquisition_date": "2026-03-01",
    "acquisition_cost": 32000,
    "salvage_value": 0,
    "useful_life_months": 36,
    "depreciation_method": "linear",
    "bas_asset_account": "1224",
    "bas_accumulated_account": "1229",
    "bas_expense_account": "7832",
    "k3_components": null,
    "opening_accumulated_depreciation": 0,
    "opening_depreciation_date": null,
    "notes": null,
    "disposed_at": null,
    "disposal_type": null,
    "disposed_proceeds": null,
    "disposal_journal_entry_id": null,
    "has_posted_depreciation": false,
    "deletable": true,
    "created_at": "2026-03-01T09:12:00.000Z",
    "updated_at": "2026-03-01T09:12:00.000Z"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/assets/:id/dispose

assets.dispose · scope bookkeeping:write

Dispose a fixed asset and post the avyttring voucher.

Marks the asset disposed (sale, scrap or business_transfer) and posts one voucher in the given fiscal period: depreciation up to disposed_at, reversal of acquisition cost and accumulated depreciation, proceeds (with output VAT for a taxable sale) and the resulting gain or loss. Investment goods over the ML 15 kap. thresholds get an input-VAT jämkning when the original VAT data is supplied. Dry-run returns the plan (lines, gain_or_loss, jämkning) without writing.

Use when: An asset has been sold, scrapped or transferred with the business and the register plus the ledger must reflect it. Run a dry-run first and show the plan to the user.

Don't use for: Correcting a register mistake (PATCH the asset). Posting annual depreciation (year-end flow). Reversing a disposal (storno the disposal voucher).

Pitfalls

  • scrap requires disposed_proceeds=0; a sale with proceeds requires vat_treatment. disposed_proceeds is gross incl. VAT for a taxable sale.
  • 409 ASSET_DISPOSAL_BLOCKED when depreciation is already posted for a later period than the one you dispose in: reverse those postings first.
  • 422 ASSET_JAMKNING_DATA_REQUIRED when the asset is an investment good and jamkning_original_input_vat + jamkning_original_deduction_percent are missing. business_transfer additionally needs business_transfer_confirmed=true and, when the obligation transfers, adjustment_document_confirmed=true.
  • The fiscal period must be open: closed or locked periods are refused by the ledger triggers.

Risk: medium · Idempotent: yes · Reversible: yes · Dry-run supported: yes

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.

Request body

NameTypeRequiredDescription
disposal_type"sale" | "scrap" | "business_transfer"yessale, scrap (utrangering) or business_transfer (verksamhetsöverlåtelse, ML 5 kap. 38 §).
disposed_atstringyesyyyy-MM-dd; the disposal voucher date.
disposed_proceedsnumberyesGross consideration incl. VAT for a taxable sale. 0 for scrap.
proceeds_accountstringnoAccount the proceeds landed on (default 1930).
fiscal_period_idstringyes
vat_treatment"standard_25" | "reverse_charge" | "export" | "exempt"noRequired for a sale with proceeds; forbidden otherwise.
jamkning_original_input_vatnumbernoOriginal input VAT at acquisition; enables the ML 15 kap. jämkning assessment together with the deduction percent.
jamkning_original_deduction_percentnumberno
business_transfer_confirmedbooleannoConfirms the transfer covers a whole business or branch (ML 5 kap. 38 §).
adjustment_document_confirmedbooleannoConfirms a justeringshandling is prepared when the jämkning obligation transfers.

Response fields

NameType
assetobject
disposal_entryobject | null
gain_or_lossnumber

Example request

{
  "disposal_type": "sale",
  "disposed_at": "2026-09-15",
  "disposed_proceeds": 12500,
  "vat_treatment": "standard_25",
  "fiscal_period_id": "fp_…"
}

Example response

{
  "data": {
    "asset": {
      "id": "0e9c…",
      "name": "MacBook Pro 16\"",
      "category": "computer",
      "acquisition_date": "2026-03-01",
      "acquisition_cost": 32000,
      "salvage_value": 0,
      "useful_life_months": 36,
      "depreciation_method": "linear",
      "bas_asset_account": "1224",
      "bas_accumulated_account": "1229",
      "bas_expense_account": "7832",
      "k3_components": null,
      "opening_accumulated_depreciation": 0,
      "opening_depreciation_date": null,
      "notes": null,
      "disposed_at": "2026-09-15",
      "disposal_type": "sale",
      "disposed_proceeds": 12500,
      "disposal_journal_entry_id": "je_…",
      "has_posted_depreciation": true,
      "deletable": false,
      "created_at": "2026-03-01T09:12:00.000Z",
      "updated_at": "2026-09-15T10:00:00.000Z"
    },
    "disposal_entry": {
      "journal_entry_id": "je_…",
      "voucher_number": 118
    },
    "gain_or_loss": -16222.22
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

PATCH /api/v1/companies/:companyId/assets/:id

assets.update · scope bookkeeping:write

Partially update a fixed asset.

Patches the register row. Name, notes, salvage value and useful life are always editable. Acquisition date, cost and category redefine the depreciation basis and are only accepted while the asset is neither disposed nor depreciated (409 ASSET_CORRECTION_BLOCKED otherwise: reverse with storno first). A category change without explicit accounts realigns the BAS triple to the new category default. Dry-runnable.

Use when: A data-entry mistake in the register, a renamed asset, or a revised useful life. Use dry-run first to see the merged row.

Don't use for: Taking the asset out of the register (POST /assets/{id}/dispose). Changing the basis after depreciation is posted (storno the postings first).

Pitfalls

  • k3_components: null clears an existing breakdown; a non-null array is validated against the acquisition_cost that will be in effect after the patch and requires K3.
  • Opening depreciation is validated against the merged row: 0 <= opening_accumulated_depreciation <= acquisition_cost - salvage_value; a positive amount needs opening_depreciation_date between acquisition_date and today (Europe/Stockholm). Zero clears the date. A positive amount cannot be combined with non-empty k3_components; component opening balances are unsupported, so keep the breakdown.
  • Opening edits post no voucher and perform no automatic reconciliation. Manually reconcile the register totals with the imported ledger before depreciation or disposal. Opening fields lock after depreciation posted through Accounted's asset register or disposal (409 ASSET_CORRECTION_BLOCKED); manual ledger postings do not lock them.
  • An empty body is rejected with 400 VALIDATION_ERROR.
  • Account overrides on a K2 company may not land on an Ej K2 account (422 K2_EXCLUDED_ACCOUNT).

Risk: low · Idempotent: yes · Reversible: yes · Dry-run supported: yes

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.

Request body

NameTypeRequiredDescription
namestringno
notesstring | nullno
category"immaterial" | "building" | "land_improvement" | "machinery" | "equipment" | "vehicle" | "computer" | "other_tangible"no
acquisition_datestringno
acquisition_costnumberno
salvage_valuenumberno
useful_life_monthsnumberno
depreciation_method"linear"no
restvarde_targetunknownno
bas_asset_accountstringno
bas_accumulated_accountstringno
bas_expense_accountstringno
k3_componentsobject[] | nullno
opening_accumulated_depreciationnumbernoAccumulated depreciation for this asset from the previous asset register, SEK, 0 to acquisition_cost - salvage_value. No voucher or automatic reconciliation: manually reconcile register totals with the imported ledger before depreciation or disposal. Manual ledger postings do not lock opening edits; depreciation posted through Accounted's asset register or disposal does. The engine plans the remaining value over the remaining useful life. A positive amount cannot be combined with non-empty k3_components. Component opening balances are unsupported; keep the component breakdown.
opening_depreciation_datestring | nullnoyyyy-MM-dd the opening accumulated depreciation is stated per. Required when the amount is above 0; not after today, not before acquisition_date.

Response fields

NameTypeDescription
namestring
category"immaterial" | "building" | "land_improvement" | "machinery" | "equipment" | "vehicle" | "computer" | "other_tangible"
acquisition_datestring
acquisition_costnumber
salvage_valuenumber
useful_life_monthsnumber
depreciation_methodstring
bas_asset_accountstring
bas_accumulated_accountstring
bas_expense_accountstring
k3_componentsobject[] | null
opening_accumulated_depreciationnumberAckumulerad avskrivning booked in a previous system before the asset entered Accounted; 0 when none. Never posted by Accounted.
opening_depreciation_datestring | null
notesstring | null
disposed_atstring | null
disposal_type"sale" | "scrap" | "business_transfer" | null
disposed_proceedsnumber | null
disposal_journal_entry_idstring | null
has_posted_depreciationbooleanTrue once any planenlig avskrivning has been posted: acquisition_date, acquisition_cost and category are then locked (ASSET_CORRECTION_BLOCKED) and a correction goes through storno.
deletablebooleanTrue while the row never reached the books (no posted depreciation, not disposed): DELETE /assets/{id} removes it. False means the row is räkenskapsinformation and leaves only through disposal or storno (409 ASSET_DELETE_BLOCKED).
created_atstring
updated_atstring
idstring

Example request

{
  "notes": "Serienummer C02XY…",
  "useful_life_months": 48
}

Example response

{
  "data": {
    "id": "0e9c…",
    "name": "MacBook Pro 16\"",
    "category": "computer",
    "acquisition_date": "2026-03-01",
    "acquisition_cost": 32000,
    "salvage_value": 0,
    "useful_life_months": 48,
    "depreciation_method": "linear",
    "bas_asset_account": "1224",
    "bas_accumulated_account": "1229",
    "bas_expense_account": "7832",
    "k3_components": null,
    "opening_accumulated_depreciation": 0,
    "opening_depreciation_date": null,
    "notes": "Serienummer C02XY…",
    "disposed_at": null,
    "disposal_type": null,
    "disposed_proceeds": null,
    "disposal_journal_entry_id": null,
    "has_posted_depreciation": false,
    "deletable": true,
    "created_at": "2026-03-01T09:12:00.000Z",
    "updated_at": "2026-03-02T08:00:00.000Z"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

DELETE /api/v1/companies/:companyId/assets/:id

assets.delete · scope bookkeeping:write

Delete an asset that never reached the books.

Removes a register row that has no posted depreciation and is not disposed, together with its own unposted depreciation drafts. No voucher is touched. A row that has reached the books is räkenskapsinformation (BFL 7 kap.) and is refused with 409 ASSET_DELETE_BLOCKED: dispose it, or reverse the posted voucher with storno first. Dry-run answers 204 without deleting, or the same 409.

Use when: A row was added by mistake (a typo, a migration test row) and deletable is true on GET. Check deletable first: it is the same rule the delete enforces.

Don't use for: Taking a real asset out of the register (POST /assets/{id}/dispose posts the avyttring voucher). Undoing posted depreciation (storno the voucher). Editing a wrong basis (PATCH).

Pitfalls

  • Idempotency-Key is mandatory.
  • 409 ASSET_DELETE_BLOCKED once any planenlig avskrivning is posted or the asset is disposed: the register row is then accounting information and leaves only through disposal or storno.
  • 204 No Content on success: there is no body to parse. A second DELETE answers 404 ASSET_NOT_FOUND.
  • Hard delete: the row is not archived. Re-create it with POST /assets if it was removed by mistake.

Risk: medium · Idempotent: no · Reversible: no · Dry-run supported: yes

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.

Example response

{
  "data": null,
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}