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_code may name another row in the same call, or an existing cost centre. A blank one means top level.
  • deactivate_missing: true makes 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_rows with every problem in error.details.errors (line = 1-based position in cost_centres).
  • dry_run: true returns 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