REST API Cost Centres - edmozley/freeitsm GitHub Wiki
๐ท๏ธ REST API: Cost centres
The usage guide for cost centres in the REST API โ the list itself, and the sync an accounting system calls. Mirrors the interactive documentation at System โ API โ Documentation. User guide: Cost centres.
[!NOTE] New to the API? The basics table on REST API: Tickets covers base URL, authentication, the response envelope, error codes, rate limits and PATCH semantics - identical across all modules.
What's distinctive about cost centres:
| ๐ข Company-scoped | Every cost centre is one company's. Lists are filtered to the key's companies; one outside them is a 404 on every by-id route. Writes land in company_id (checked against the key) or the key's default company. |
| ๐ค Codes are text | "0010" stays "0010". Unique per company, ignoring case. Send codes as JSON strings, never numbers. |
| ๐ One call keeps you in step | POST /cost-centres/sync takes the whole list, matched on code โ added, updated, nothing duplicated. All or nothing. |
๐ Quick start
B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โฆ"
# Active cost centres, by code
curl -s -H "$K" "$B/cost-centres?active=true" | jq '.data[] | {code, name}'
# Nightly sync from finance - try it first with dry_run
curl -s -H "$K" -H "Content-Type: application/json" -X POST "$B/cost-centres/sync" -d '{
"dry_run": true,
"deactivate_missing": true,
"cost_centres": [
{"code": "0010", "name": "IT"},
{"code": "0011", "name": "IT - Infrastructure", "parent_code": "0010"},
{"code": "N1414", "name": "Facilities", "is_active": true}
]}'
Endpoints
| Method | Path | Permission | What |
|---|---|---|---|
| GET | /cost-centres |
cost_centres.read | List / search |
| POST | /cost-centres |
cost_centres.create | Add one |
| GET | /cost-centres/{id} |
cost_centres.read | One cost centre |
| PATCH | /cost-centres/{id} |
cost_centres.update | Change fields |
| DELETE | /cost-centres/{id} |
cost_centres.delete | Delete (refused with 409 while it has children - make it inactive instead) |
| POST | /cost-centres/sync |
cost_centres.update and create | Bring the whole list in step |
List filters
company_id, code (exact), q (code or name), active=true|false, parent_id (0 = top level), sort (code default, name, updated_at, id; prefix - for descending), page / per_page.
A cost centre
{
"id": 7, "code": "0011", "name": "IT - Infrastructure", "description": null,
"parent": { "id": 6, "code": "0010", "name": "IT" },
"is_active": true,
"company": { "id": 1, "name": "Default" },
"child_count": 0,
"created_at": "2026-10-03T09:12:00Z", "updated_at": "2026-10-03T09:12:00Z"
}
Writes take code, name, description, parent_id (same company; never itself or anything below it), is_active, and on create company_id.
The sync
Body: cost_centres (array, at most 10,000 โ split bigger lists by company), each with code and any of name, description, parent_code, is_active; optional company_id, dry_run, deactivate_missing.
- Matched on code, ignoring case. A new code needs a
name. Only the keys you send are changed. parent_codemay name another row in the same call, or an existing cost centre. A blank one means top level.deactivate_missing: truemakes inactive every cost centre of that company not in the list โ for when the list is complete. Nothing is ever deleted.- All or nothing. If any row has a problem, nothing is written and you get 422
invalid_rowswith every problem inerror.details.errors(line= 1-based position incost_centres). dry_run: truereturns what would happen and writes nothing.
Response: company_id, applied, dry_run, counts (create, update, unchanged, deactivate) and changes โ one entry per row that changed, with its line, code, action and the fields that changed (line is null for one made inactive because it was missing).
See also: Cost centres ยท Cost centres โ Developer Guide ยท REST API