REST API CMDB - edmozley/freeitsm GitHub Wiki
๐๏ธ REST API: CMDB
The complete usage guide for the CMDB module of the REST API โ classes, typed properties, configuration items, relationships, impact analysis and ticket links. Mirrors the interactive documentation at System โ API โ Documentation (with its live "Try it" tester).
[!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 the CMDB:
| ๐งฌ Schema-driven | Every class defines typed properties (text, number, date, boolean, dropdown, object_ref). Read the class first (GET /cmdb/classes/{id}), then write objects with a friendly property_key โ value map โ the API validates types, required flags, dropdown options and object_ref target classes. |
| ๐ณ Hierarchy + graph | Objects nest via parent_id (cycle-guarded) and connect via directed relationships with verb/inverse-verb pairs ("depends on" / "is depended on by"). |
| ๐ฅ Deletes take the tree | Deleting an object removes its whole descendant tree, properties, relationships and ticket links (the module's design). Check GET .../impact first โ the response tells you deleted_descendants. |
| ๐ก๏ธ Ticket links are company-scoped | The internal CMDB screen reads linked tickets unscoped (a known multi-tenancy gap); the API deliberately does not reproduce that โ GET /cmdb/objects/{id}/tickets honours the key's company scope, and link/unlink gate the ticket. |
| ๐๏ธ Classes are read-only in v1 | Class design (properties, options, icons) stays an admin activity in the UI; the API reads definitions so integrations can build valid writes. |
๐ Quick start
Discover the shape, then create a CI with validated properties:
B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โฆ"
# 1. What does a "server" need?
curl -s -H "$K" "$B/cmdb/classes" | jq '.data[] | {id, class_key, name}'
curl -s -H "$K" "$B/cmdb/classes/12" | jq '.data.properties[] | {property_key, type, is_required}'
# 2. Create it (required properties enforced; dropdowns validated against the option list)
curl -s -X POST "$B/cmdb/objects" -H "$K" -H "Content-Type: application/json" -d '{
"name": "SQL01", "class_key": "server",
"properties": { "hostname": "sql01.corp.local", "os": "Windows Server 2022" }
}'
# 3. Wire it into the graph
curl -s -X POST "$B/cmdb/objects/44/relationships" -H "$K" -H "Content-Type: application/json" \
-d '{"to_object_id": 12, "verb": "depends on"}'
๐งฌ Classes
๐ข GET /cmdb/classes ย ๐ cmdb_classes.read
All CI classes with class_key, icon, active flag and object counts.
๐ข GET /cmdb/classes/{id} ย ๐ cmdb_classes.read
The class plus its full property definitions โ everything needed to build a valid write:
{ "data": { "id": 12, "class_key": "server", "name": "Server",
"properties": [
{ "id": 40, "property_key": "hostname", "label": "Hostname", "type": "text",
"is_required": true, "target_class": null, "options": [] },
{ "id": 41, "property_key": "os", "label": "OS", "type": "dropdown",
"is_required": false, "target_class": null,
"options": [ { "value": "Windows Server 2022", "colour": null }, โฆ ] } ] } }
๐๏ธ Objects
๐ข GET /cmdb/objects โ list / search ย ๐ cmdb_objects.read
| Parameter | Description |
|---|---|
class_id / class_key |
Filter by class |
q |
Search by name |
parent_id |
Children of an object ยท top_level=true for roots |
is_planned |
true / false โ planned vs live CIs |
sort |
name (default), id, created_at, updated_at โ prefix - for descending |
page / per_page |
Pagination โ default 1 / 25, max 100 |
๐ต POST /cmdb/objects โ create ย ๐ cmdb_objects.create
name + class_id/class_key required. properties is a map keyed by property_key. Validation mirrors the UI exactly โ plus one improvement:
- required properties enforced on create (
422naming the missing label) numbermust be numeric ยทdatemust parse (ISO 8601) ยทbooleancoerces sensiblyobject_refmust exist, can't self-reference, and must match the property's target class- dropdown values must be one of the property's options (the UI stores anything โ the API doesn't)
The class is immutable after creation, like the UI. Returns 201.
๐ข GET /cmdb/objects/{id} โ get one ย ๐ cmdb_objects.read
Fully hydrated: every class property with its typed value (object_ref values come with an embedded {id, name, class_name} card), parent, children, relationships.outgoing/incoming with natural-reading verbs, and the cached ai_summary.
๐ PATCH /cmdb/objects/{id} โ update ย ๐ cmdb_objects.update
Update name, parent_id (existence + cycle-walk guard โ you can't parent an object to its own descendant), is_planned, and any subset of properties โ only the keys you send are touched (required checks apply only to sent properties, matching the UI's inline edit). Empty/null clears a property.
๐ด DELETE /cmdb/objects/{id} โ delete ย ๐ cmdb_objects.delete
[!WARNING] Takes the whole tree. The object, all its descendants, their property values, relationships and ticket links are permanently removed (object_ref properties elsewhere that pointed at them are cleared). The response reports
deleted_descendantsโ runGET .../impactfirst if you're not sure.
๐ข GET /cmdb/objects/{id}/impact โ impact analysis ย ๐ cmdb_objects.read
The blast radius before you touch something:
{ "data": { "descendants": [ { "id": 45, "name": "NODE1", "class_name": "Server", "depth": 1 } ],
"referenced_by_property": [ { "id": 7, "name": "Payroll", "class_name": "Application", "property": "Runs on" } ],
"incoming_relationships": [ { "id": 45, "name": "NODE1", "class_name": "Server", "relationship": "is depended on by" } ] } }
๐ Relationships
๐ต POST /cmdb/objects/{id}/relationships ย ๐ cmdb_relationships.create
Creates a directed edge from this object: {"to_object_id": 12, "verb": "depends on"} (or relationship_type_id). No self-links (422); the same from/to/type triple twice โ 409. The other side automatically reads with the inverse verb.
๐ด DELETE /cmdb/objects/{id}/relationships/{rel_id} ย ๐ cmdb_relationships.delete
Removes the edge โ it must involve this object (either direction).
๐ซ Ticket links
๐ข GET /cmdb/objects/{id}/tickets ย ๐ cmdb_ticket_links.read
The tickets linked to this CI โ scoped to the key's companies (deliberately tighter than the internal endpoint).
๐ต POST /cmdb/objects/{id}/tickets ย ๐ cmdb_ticket_links.create
Body: {"ticket_id": 141}. The ticket must be within the key's company scope (404 otherwise); already linked โ 409.
๐ด DELETE /cmdb/objects/{id}/tickets/{ticket_id} ย ๐ cmdb_ticket_links.delete
Removes the link.
๐ Reference data
| Endpoint | Permission | Returns |
|---|---|---|
๐ข GET /cmdb-relationship-types |
๐ reference.read |
Verb + inverse-verb pairs (seeded: depends on, connects to, managed by) |
๐งช Worked example: discovery-tool sync
A network-discovery job upserting CIs and wiring dependencies (cmdb_classes: read + cmdb_objects: read/create/update + cmdb_relationships: create):
B="https://your-server/api/v1"; K="Authorization: Bearer fitsm_โฆ"
# Upsert-by-name within the server class
ID=$(curl -s -H "$K" "$B/cmdb/objects?class_key=server&q=sql01" | jq -r '.data[0].id // empty')
if [ -n "$ID" ]; then
curl -s -X PATCH "$B/cmdb/objects/$ID" -H "$K" -H "Content-Type: application/json" \
-d '{"properties": {"os": "Windows Server 2022"}}'
else
ID=$(curl -s -X POST "$B/cmdb/objects" -H "$K" -H "Content-Type: application/json" \
-d '{"name":"SQL01","class_key":"server","properties":{"hostname":"sql01.corp.local"}}' | jq -r '.data.id')
fi
# The app depends on the freshly-synced server
curl -s -X POST "$B/cmdb/objects/$APP_ID/relationships" -H "$K" -H "Content-Type: application/json" \
-d "{\"to_object_id\": $ID, \"verb\": \"depends on\"}"
And change-risk enrichment โ what breaks if we reboot this?
curl -s -H "$K" "$B/cmdb/objects/$ID/impact" \
| jq -r '.data.incoming_relationships[] | "\(.class_name): \(.name) (\(.relationship))"'
Under the hood: REST API โ How It Works ยท Other modules: Tickets ยท Assets ยท Problems ยท Changes ยท Knowledge ยท Tasks ยท Keys & permissions: System โ API (System module) ยท Module docs: CMDB.