Articles
The price list (artikelregister) invoices are built from: what you sell, its price in öre, its VAT rate, its BAS account and whether it can carry a ROT/RUT deduction. Adding an article to an invoice line copies those onto the line, so changing an article later never changes an invoice already written.
The article number is the key bookkeepers use. It is unique in the organization and stays reserved by a deleted article, so to keep a price list in step with an ERP, look the article up by number (GET /articles?q=) and update it, or create it when it is missing.
List articles
/articlesArticles in article-number order, the order of a printed price list. Deleted articles are not listed; deactivated ones are, unless you filter on filter[active]=true.
q is a case-insensitive contains match on the name and the article number, so 1042 finds ART-1042.
Paging is by cursor: pass meta.next_cursor back as cursor together with the same filters and limit — the URLs in links do not carry your filters.
curl 'https://api.closepact.com/v1/api/articles' \
-H "Authorization: Bearer $CLOSEPACT_API_KEY"{
"data": [
{
"id": "01a159f8-2d6a-7b3e-9f1c-8e4a2d7b5c63",
"article_number": "ST-100",
"name": "Hemstädning",
"description": "Städning i hemmet enligt checklista. RUT-berättigad.",
"type": "hour",
"unit": "tim",
"pricing": {
"unit_price_cents": 45000,
"currency": "SEK",
"vat_rate": 25
},
"account_code": "3001",
"rot_rut_eligible": true,
"deductible": true,
"line_type": "labour",
"is_active": true,
"metadata": [],
"created_at": "2026-09-01T07:30:00+00:00",
"updated_at": "2026-09-01T07:30:00+00:00",
"deleted_at": null
},
{
"id": "01a159f8-2d84-7c51-a2e6-3f9b1d8c4e70",
"article_number": "ST-210",
"name": "Trappstädning, per uppgång",
"description": null,
"type": "service",
"unit": "st",
"pricing": {
"unit_price_cents": 95000,
"currency": "SEK",
"vat_rate": 25
},
"account_code": "3001",
"rot_rut_eligible": false,
"deductible": false,
"line_type": "service",
"is_active": true,
"metadata": [],
"created_at": "2026-09-01T07:31:12+00:00",
"updated_at": "2026-09-01T07:31:12+00:00",
"deleted_at": null
}
],
"links": {
"first": null,
"last": null,
"prev": null,
"next": null
},
"meta": {
"path": "https://api.closepact.com/v1/api/articles",
"per_page": 50,
"next_cursor": null,
"prev_cursor": null
}
}Query parameters
qstringSearch the name and the article number.
Example
städfilter[type]string | array of stringsOne type, or several as
filter[type][]=hour&filter[type][]=service.filter[active]booleantruefor articles that can be picked for new lines,falsefor deactivated ones.filter[rot_rut_eligible]booleanOnly articles that can, or cannot, carry a ROT/RUT deduction.
filter[account_code]stringOnly articles booked to this BAS account.
Example
3001limitintegerArticles per page.
Default
501–100cursorstringOpaque cursor from
meta.next_cursorormeta.prev_cursorof the previous page.
Responses
Headers
X-RateLimit-Limit— Requests this key may make per minute.X-RateLimit-Remaining— Requests left in the current minute.
dataarray of objectsrequiredidstring(uuid)requiredarticle_numberstringrequiredArtikelnummer, unique in the organization.
namestringrequiredBecomes the line's description.
descriptionstringnullablerequiredtypestringrequiredOne of
goodsservicehourfeeunitstringnullablerequirede.g.
tim,st,kvm.pricingobjectrequiredaccount_codestringnullablerequiredBAS sales account.
rot_rut_eligiblebooleanrequiredOnly ever true for
hourandservicearticles.deductiblebooleanrequiredWhether a line built from it counts towards a ROT/RUT deduction: eligible and labour. The field to rely on.
line_typestringrequiredWhat an invoice line built from it becomes.
One of
goodsservicelabourfeeis_activebooleanrequiredFalse once deactivated; still resolvable, no longer offered.
metadataobject | array of valuesnullablerequiredFree-form; an empty list when unused.
created_atstring(date-time)nullablerequiredupdated_atstring(date-time)nullablerequireddeleted_atstring(date-time)nullablerequired
linksobjectrequiredmetaobjectrequired
- 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.Errors
- 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs:Errors
featurenames the capability (the operation'sx-feature) andrequired_tierthe cheapest tier that grants it. Every operation answers this with"feature": "core.api"when no module the organization holds is on a tier that includes the API. - 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (Errors
module_seat_required— an administrator assigns seats under Settings → Users), or the organization is suspended. - 429The key has made more requests this minute than its limit allows.Errors
Create an article
/articlesAdds an article to the price list. article_number and name are required; the rest defaults to a 25 % goods article priced at 0 kr in SEK.
- Price is
unit_price_cents, a whole number of öre excluding VAT: 450,00 kr is45000. A decimal is refused, because it is almost always kronor sent by mistake. - VAT must be 25, 12, 6 or 0; anything else is a 422 that names the four rates.
- Type decides what a line built from the article becomes:
hour→labour,service→service,fee→fee,goods→goods. - ROT/RUT.
rot_rut_eligibleis kept only forhourandservicearticles — ROT and RUT cover work, never materials — and it is cleared whenever the type stops qualifying.deductiblein the response is the answer to rely on. - Account is the BAS sales account, e.g.
3001. Left empty, a line built from the article gets the standard account for its VAT rate (3001, 3002, 3003).
An article number that is already taken — also by a deleted article — answers 409 naming the article that holds it.
curl -X POST 'https://api.closepact.com/v1/api/articles' \
-H "Authorization: Bearer $CLOSEPACT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"article_number": "ST-100",
"name": "Hemstädning",
"description": "Städning i hemmet enligt checklista. RUT-berättigad.",
"type": "hour",
"unit": "tim",
"unit_price_cents": 45000,
"vat_rate": 25,
"account_code": "3001",
"rot_rut_eligible": true
}'{
"data": {
"id": "01a159f8-2d6a-7b3e-9f1c-8e4a2d7b5c63",
"article_number": "ST-100",
"name": "Hemstädning",
"description": "Städning i hemmet enligt checklista. RUT-berättigad.",
"type": "hour",
"unit": "tim",
"pricing": {
"unit_price_cents": 45000,
"currency": "SEK",
"vat_rate": 25
},
"account_code": "3001",
"rot_rut_eligible": true,
"deductible": true,
"line_type": "labour",
"is_active": true,
"metadata": [],
"created_at": "2026-10-18T09:00:00+00:00",
"updated_at": "2026-10-18T09:00:00+00:00",
"deleted_at": null
}
}Request body
application/json · required
The writable fields of an article. On update every field is optional.
article_numberstringrequiredat most 32 characters
namestringrequiredat most 200 characters
descriptionstringnullableat most 2,000 characters
typestringOne of
goodsservicehourfeeDefault
"goods"unitstringnullableat most 32 characters
unit_price_centsintegerÖre, excluding VAT.
Default
0≥ 0currencystringDefault
"SEK"exactly 3 charactersvat_ratenumberOne of
251260Default
25account_codestringnullableat most 8 characters
rot_rut_eligiblebooleanKept only for
hourandservicearticles.Default
falseis_activebooleanDefault
truesub_entity_idstring(uuid)nullablemetadataobject
Responses
Headers
X-RateLimit-Limit— Requests this key may make per minute.X-RateLimit-Remaining— Requests left in the current minute.
dataobjectrequiredAn article in the price list.
idstring(uuid)requiredarticle_numberstringrequiredArtikelnummer, unique in the organization.
namestringrequiredBecomes the line's description.
descriptionstringnullablerequiredtypestringrequiredOne of
goodsservicehourfeeunitstringnullablerequirede.g.
tim,st,kvm.pricingobjectrequiredaccount_codestringnullablerequiredBAS sales account.
rot_rut_eligiblebooleanrequiredOnly ever true for
hourandservicearticles.deductiblebooleanrequiredWhether a line built from it counts towards a ROT/RUT deduction: eligible and labour. The field to rely on.
line_typestringrequiredWhat an invoice line built from it becomes.
One of
goodsservicelabourfeeis_activebooleanrequiredFalse once deactivated; still resolvable, no longer offered.
metadataobject | array of valuesnullablerequiredFree-form; an empty list when unused.
created_atstring(date-time)nullablerequiredupdated_atstring(date-time)nullablerequireddeleted_atstring(date-time)nullablerequired
- 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.Errors
- 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs:Errors
featurenames the capability (the operation'sx-feature) andrequired_tierthe cheapest tier that grants it. Every operation answers this with"feature": "core.api"when no module the organization holds is on a tier that includes the API. - 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (Errors
module_seat_required— an administrator assigns seats under Settings → Users), or the organization is suspended. - 409Another article — possibly a deleted one — already has this article number.Errors
errorisconflict; the message names the article that holds the number. - 422The request body or query failed validation.Errors
- 429The key has made more requests this minute than its limit allows.Errors
Get an article
/articles/{article}One article. A deleted article answers 404, like another organization's.
curl 'https://api.closepact.com/v1/api/articles/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
-H "Authorization: Bearer $CLOSEPACT_API_KEY"{
"data": {
"id": "01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40",
"article_number": "string",
"name": "Anna Lindqvist",
"description": "A short description.",
"type": "goods",
"unit": "string",
"pricing": {
"unit_price_cents": 125000,
"currency": "SEK",
"vat_rate": 25
},
"account_code": "string",
"rot_rut_eligible": true,
"deductible": true,
"line_type": "goods",
"is_active": true,
"metadata": {},
"created_at": "2026-10-18T09:30:00Z",
"updated_at": "2026-10-18T09:30:00Z",
"deleted_at": "2026-10-18T09:30:00Z"
}
}Path parameters
articlestring(uuid)requiredThe article's id.
Responses
Headers
X-RateLimit-Limit— Requests this key may make per minute.X-RateLimit-Remaining— Requests left in the current minute.
dataobjectrequiredAn article in the price list.
idstring(uuid)requiredarticle_numberstringrequiredArtikelnummer, unique in the organization.
namestringrequiredBecomes the line's description.
descriptionstringnullablerequiredtypestringrequiredOne of
goodsservicehourfeeunitstringnullablerequirede.g.
tim,st,kvm.pricingobjectrequiredaccount_codestringnullablerequiredBAS sales account.
rot_rut_eligiblebooleanrequiredOnly ever true for
hourandservicearticles.deductiblebooleanrequiredWhether a line built from it counts towards a ROT/RUT deduction: eligible and labour. The field to rely on.
line_typestringrequiredWhat an invoice line built from it becomes.
One of
goodsservicelabourfeeis_activebooleanrequiredFalse once deactivated; still resolvable, no longer offered.
metadataobject | array of valuesnullablerequiredFree-form; an empty list when unused.
created_atstring(date-time)nullablerequiredupdated_atstring(date-time)nullablerequireddeleted_atstring(date-time)nullablerequired
- 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.Errors
- 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs:Errors
featurenames the capability (the operation'sx-feature) andrequired_tierthe cheapest tier that grants it. Every operation answers this with"feature": "core.api"when no module the organization holds is on a tier that includes the API. - 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (Errors
module_seat_required— an administrator assigns seats under Settings → Users), or the organization is suspended. - 404No such record in this organization.Errors
- 429The key has made more requests this minute than its limit allows.Errors
Update an article
/articles/{article}Changes only the fields you send. A new price applies to lines added from now on; existing invoice lines keep the price they were given. ROT/RUT eligibility is re-derived on every update, so changing an hour article to goods takes the deduction off it. Renumbering to a number that is taken answers 409.
curl -X PATCH 'https://api.closepact.com/v1/api/articles/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
-H "Authorization: Bearer $CLOSEPACT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"unit_price_cents": 47500
}'{
"data": {
"id": "01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40",
"article_number": "string",
"name": "Anna Lindqvist",
"description": "A short description.",
"type": "goods",
"unit": "string",
"pricing": {
"unit_price_cents": 125000,
"currency": "SEK",
"vat_rate": 25
},
"account_code": "string",
"rot_rut_eligible": true,
"deductible": true,
"line_type": "goods",
"is_active": true,
"metadata": {},
"created_at": "2026-10-18T09:30:00Z",
"updated_at": "2026-10-18T09:30:00Z",
"deleted_at": "2026-10-18T09:30:00Z"
}
}Path parameters
articlestring(uuid)requiredThe article's id.
Request body
application/json · required
The writable fields of an article. On update every field is optional.
article_numberstringat most 32 characters
namestringat most 200 characters
descriptionstringnullableat most 2,000 characters
typestringOne of
goodsservicehourfeeDefault
"goods"unitstringnullableat most 32 characters
unit_price_centsintegerÖre, excluding VAT.
Default
0≥ 0currencystringDefault
"SEK"exactly 3 charactersvat_ratenumberOne of
251260Default
25account_codestringnullableat most 8 characters
rot_rut_eligiblebooleanKept only for
hourandservicearticles.Default
falseis_activebooleanDefault
truesub_entity_idstring(uuid)nullablemetadataobject
Responses
Headers
X-RateLimit-Limit— Requests this key may make per minute.X-RateLimit-Remaining— Requests left in the current minute.
dataobjectrequiredAn article in the price list.
idstring(uuid)requiredarticle_numberstringrequiredArtikelnummer, unique in the organization.
namestringrequiredBecomes the line's description.
descriptionstringnullablerequiredtypestringrequiredOne of
goodsservicehourfeeunitstringnullablerequirede.g.
tim,st,kvm.pricingobjectrequiredaccount_codestringnullablerequiredBAS sales account.
rot_rut_eligiblebooleanrequiredOnly ever true for
hourandservicearticles.deductiblebooleanrequiredWhether a line built from it counts towards a ROT/RUT deduction: eligible and labour. The field to rely on.
line_typestringrequiredWhat an invoice line built from it becomes.
One of
goodsservicelabourfeeis_activebooleanrequiredFalse once deactivated; still resolvable, no longer offered.
metadataobject | array of valuesnullablerequiredFree-form; an empty list when unused.
created_atstring(date-time)nullablerequiredupdated_atstring(date-time)nullablerequireddeleted_atstring(date-time)nullablerequired
- 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.Errors
- 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs:Errors
featurenames the capability (the operation'sx-feature) andrequired_tierthe cheapest tier that grants it. Every operation answers this with"feature": "core.api"when no module the organization holds is on a tier that includes the API. - 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (Errors
module_seat_required— an administrator assigns seats under Settings → Users), or the organization is suspended. - 404No such record in this organization.Errors
- 409Another article — possibly a deleted one — already has this article number.Errors
errorisconflict; the message names the article that holds the number. - 422The request body or query failed validation.Errors
- 429The key has made more requests this minute than its limit allows.Errors
Delete an article
/articles/{article}Removes the article — unless it appears on an issued invoice. Those have to be reproducible for seven years, so such an article is deactivated instead: it stays resolvable from the invoice lines and disappears from the articles people pick from. The response says which of the two happened and why.
Either way its number stays reserved. Drafts do not count; a draft can still be changed.
curl -X DELETE 'https://api.closepact.com/v1/api/articles/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
-H "Authorization: Bearer $CLOSEPACT_API_KEY"{
"data": {
"deleted": true,
"deactivated": false,
"issued_invoice_lines": 0,
"reason": null
}
}Path parameters
articlestring(uuid)requiredThe article's id.
Responses
Headers
X-RateLimit-Limit— Requests this key may make per minute.X-RateLimit-Remaining— Requests left in the current minute.
dataobjectrequireddeletedbooleanrequireddeactivatedbooleanrequiredTrue when the article was kept and deactivated instead.
issued_invoice_linesintegerrequiredHow many issued invoice lines use it.
reasonstringnullablerequired
- 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.Errors
- 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs:Errors
featurenames the capability (the operation'sx-feature) andrequired_tierthe cheapest tier that grants it. Every operation answers this with"feature": "core.api"when no module the organization holds is on a tier that includes the API. - 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (Errors
module_seat_required— an administrator assigns seats under Settings → Users), or the organization is suspended. - 404No such record in this organization.Errors
- 429The key has made more requests this minute than its limit allows.Errors