Objects Endpoints
Base path: /api/v1/objects — needs the API role objects or all.
These endpoints read, create, update and delete hosts (and objects) inside the syncer from external systems. This is the way to feed a CMDB the syncer has no importer for.
Note
There is no PUT method. The syncer gets or creates the host from its
database on POST, so you never have to check whether a host exists first.
GET /api/v1/objects/<hostname>
Return labels, inventory and the import timestamps of one host.
curl -u "user:password" \
https://cmdbsyncer.example.com/api/v1/objects/srv-web01
{
"hostname": "srv-web01",
"labels": {"os": "linux", "location": "muc"},
"inventory": {"checkmk": {"folder": "/muc"}},
"last_seen": "2026-04-26T17:55:00Z",
"last_update": "2026-04-26T17:55:00Z"
}
last_seen is the last time an import saw the host, last_update the last time
an import actually changed it. Both are false when the host was never imported.
Unknown hosts — and hosts outside the caller's scope — answer 404.
POST /api/v1/objects/<hostname>
Create or update a host and bind it to an account.
| Field | Required | Description |
|---|---|---|
account |
yes | Name of an existing account. An unknown name returns 400. |
labels |
yes | Flat key/value attributes. An empty object is valid. |
curl -u "user:password" \
-H "Content-Type: application/json" \
-d '{"account": "my_import", "labels": {"os": "linux", "location": "muc"}}' \
https://cmdbsyncer.example.com/api/v1/objects/srv-web01
{"status": "saved"}
A host that already belongs to a different account is not touched; the call
returns 403 with {"status": "account_conflict"}. Re-binding a host to another
account is done in the admin interface, not over the API.
DELETE /api/v1/objects/<hostname>
Archive the host. Since 4.3 the host is soft-deleted — it moves to the Archive view and can be restored — instead of being removed permanently. If the host frees a seat in a Checkmk folder pool, the seat is given back.
curl -u "user:password" -X DELETE \
https://cmdbsyncer.example.com/api/v1/objects/srv-web01
{"status": "deleted"}
POST /api/v1/objects/bulk
Create or update many hosts under one account in a single call. Use this instead of a loop over the single-host endpoint — it is far faster for a full import run.
| Field | Required | Description |
|---|---|---|
account |
yes | Account that owns every host in this batch |
objects |
yes | List of {"hostname": ..., "labels": {...}} |
curl -u "user:password" \
-H "Content-Type: application/json" \
-d '{
"account": "my_import",
"objects": [
{"hostname": "srv-web01", "labels": {"os": "linux"}},
{"hostname": "srv-web02", "labels": {"os": "linux"}}
]
}' \
https://cmdbsyncer.example.com/api/v1/objects/bulk
{"status": "saved 2", "not-saved": []}
The call does not abort on a single bad host: hosts that belong to another
account (or that the caller may not write) are listed in not-saved, everything
else is saved.
POST /api/v1/objects/<hostname>/inventory
Replace one inventory section of a host.
| Field | Required | Description |
|---|---|---|
key |
yes | Top-level inventory key, e.g. checkmk, netbox, my_cmdb |
inventory |
yes | Nested payload stored below that key |
curl -u "user:password" \
-H "Content-Type: application/json" \
-d '{"key": "my_cmdb", "inventory": {"owner": "team-web", "sla": "gold"}}' \
https://cmdbsyncer.example.com/api/v1/objects/srv-web01/inventory
{"status": "saved"}
Warning
Inventory writes never create a host — an unknown hostname returns 404.
Create the host through POST /api/v1/objects/<hostname> first, so it gets
a proper account binding.
Keys must be valid MongoDB keys: no leading $ and no dots. A rejected key
returns 400.
POST /api/v1/objects/bulk/inventory
Write inventory sections for many hosts at once.
curl -u "user:password" \
-H "Content-Type: application/json" \
-d '{
"inventories": [
{"hostname": "srv-web01", "key": "my_cmdb", "inventory": {"sla": "gold"}},
{"hostname": "srv-web02", "key": "my_cmdb", "inventory": {"sla": "bronze"}}
]
}' \
https://cmdbsyncer.example.com/api/v1/objects/bulk/inventory
{"status": "saved 2", "not-found": []}
Every item is validated before the first write, so one bad key aborts the
whole batch with 400 instead of leaving half of it saved. Hostnames that do not
exist are not an error — they come back in not-found.
GET /api/v1/objects/all
Paginated listing of every host (objects excluded).
| Parameter | Default | Description |
|---|---|---|
start |
1 |
Zero-based offset |
limit |
100 |
Page size, maximum 10000 |
curl -u "user:password" \
"https://cmdbsyncer.example.com/api/v1/objects/all?start=0&limit=500"
{
"results": [{"hostname": "srv-web01", "labels": {}, "inventory": {}, "last_seen": "...", "last_update": "..."}],
"start": 0,
"limit": 500,
"size": 12043,
"_links": {
"next": "/api/v1/objects/all?limit=500&start=500",
"prev": "/api/v1/objects/all?limit=500&start=0"
}
}
Follow _links.next until it is no longer present — that is the last page.
Non-numeric or negative parameters, and a limit above 10000, return 400.
Relations
Since 4.1
Typed relations between hosts. These endpoints only exist when CMDB_MODE = True
is set in local_config.py; otherwise they answer 404. Available types are
depends_on, runs_on, member_of, parent_of and connects_to.
GET /api/v1/objects/<hostname>/relations
{
"hostname": "srv-web01",
"outgoing": [
{"type": "runs_on", "type_label": "Runs on", "target": "esx-01", "source": "manual"}
],
"inbound": [
{"type": "depends_on", "type_label": "Required by", "target": "srv-app01", "source": "import"}
]
}
Outgoing edges are stored on the host itself, inbound edges are looked up from the other side and are read-only here — change them on their source host.
POST /api/v1/objects/<hostname>/relations
Add an edge from hostname to target.
| Field | Required | Description |
|---|---|---|
type |
yes | One of the relation types above |
target |
yes | Hostname of the target object |
source |
no | Provenance tag, default manual. Importers set their own tag so they can later prune their own edges without touching manual ones. |
curl -u "user:password" \
-H "Content-Type: application/json" \
-d '{"type": "runs_on", "target": "esx-01"}' \
https://cmdbsyncer.example.com/api/v1/objects/srv-web01/relations
{"status": "added"}
An edge that already exists answers {"status": "unchanged"}. An unknown type or
a host pointing at itself returns 400.
DELETE /api/v1/objects/<hostname>/relations
Same body as POST (type and target); removes the edge and answers
{"status": "removed"}, or {"status": "unchanged"} if there was nothing to
remove.