Skip to main content

Topology API

These endpoints manage the topology graph (business services, applications, components, hosts, databases, clusters) and the metric bindings that connect data to it. The concepts are in Topology & CMDB Integration.

There are two ways in:

  • POST /v1/topology — the machine-to-machine bulk push for CMDB sync. Idempotent, transactional, external-ID addressed. This is what most integrations use.
  • /api/topology/... — fine-grained CRUD used by the console.

Permissions: reads require CanViewAlerts; all writes (including the push) require topology write permission (CanManageRules).

Node & edge types

nodeTypeMeaning
BusinessServiceA customer- or business-facing service (the unit of impact).
ApplicationThe logical representation of a business application.
ComponentAn operational deployment unit — a runtime boundary that emits telemetry (a farm, tier, cluster, …); not necessarily a single microservice.
HostA machine — server, VM, or node.
DatabaseA data-tier dependency.
ClusterA homogeneous redundancy group ("farm") of like members.

Other is not accepted (it is a reserved client-side rendering fallback); unknown node types are rejected.

edgeTypeMeaning
containsHierarchical containment (the browsable tree), parent → child.
depends_onRuntime dependency, source → target.
runs_onHosting/placement, workload → infrastructure (Host/Cluster).
routes_toLoad-balanced distribution toward redundant members.

POST /v1/topology — CMDB bulk push

Synchronous, idempotent, transactional upsert. Clients reference everything by their own stable externalId; Lumetry numeric IDs are never required.

Request

{
"source": "servicenow",
"importId": "servicenow-2026-06-02T09:00:00Z",
"nodes": [
{
"externalId": "servicenow:svc:mobile-banking",
"nodeType": "BusinessService",
"displayName": "Mobile Banking",
"environment": "production",
"ownerTeam": "channels-platform",
"metadata": { "cmdbClass": "cmdb_ci_service", "sysId": "2cdd4c4f" }
},
{
"externalId": "servicenow:app:mobile-application",
"nodeType": "Application",
"displayName": "Mobile Application",
"environment": "production"
},
{
"externalId": "servicenow:cmp:mobile-frontend",
"nodeType": "Component",
"displayName": "Mobile Frontend",
"environment": "production"
},
{
"externalId": "servicenow:host:host01",
"nodeType": "Host",
"displayName": "host01",
"environment": "production"
}
],
"edges": [
{ "sourceExternalId": "servicenow:svc:mobile-banking", "targetExternalId": "servicenow:app:mobile-application", "edgeType": "contains" },
{ "sourceExternalId": "servicenow:app:mobile-application", "targetExternalId": "servicenow:cmp:mobile-frontend", "edgeType": "contains" },
{ "sourceExternalId": "servicenow:cmp:mobile-frontend", "targetExternalId": "servicenow:host:host01", "edgeType": "runs_on" }
],
"metricBindings": [
{ "metricId": "mobile.frontend.latency.p95", "nodeExternalId": "servicenow:cmp:mobile-frontend", "bindingType": "emits" }
]
}
FieldRequiredMeaning
sourceyesOriginating CMDB name (servicenow, bmc-helix, device42, custom-cmdb, …).
importIdnoCaller-generated run identifier for traceability.
nodes[]noNodes to create/update. externalId, nodeType, displayName required; environment, ownerTeam, metadata (JSON object) optional.
edges[]noRelationships. Referenced nodes must exist already or be in the same payload.
metricBindings[]noMetric-to-node bindings. metricId must match an existing metric key; the push does not create metric definitions.

Modeling tips

  • A Component may runs_on several Hosts, and one Host may carry several Components — send one runs_on edge per pair.
  • Model hosting as Component/Application/Database runs_on Host/Cluster, never the reverse. Infrastructure cannot depend "upward" on applications or components.
  • For a farm, send Cluster contains Host for the members and routes_to for the load-balanced front.

Behavior

  • Upsert keys: nodes by externalId; edges by (sourceExternalId, targetExternalId, edgeType); bindings by (metricId, nodeExternalId).
  • Idempotent: re-sending the same payload creates no duplicates.
  • Upsert-only: it does not prune nodes/edges/bindings missing from a later payload.
  • Transactional: the entire payload is validated and applied in one transaction; on any validation error, nothing is written.

Response 200

{
"source": "servicenow",
"importId": "servicenow-2026-06-02T09:00:00Z",
"importedAt": "2026-06-02T09:00:01.318Z",
"nodesReceived": 4, "nodesCreated": 4, "nodesUpdated": 0, "nodesUnchanged": 0,
"edgesReceived": 3, "edgesCreated": 3, "edgesUpdated": 0, "edgesUnchanged": 0,
"metricBindingsReceived": 1, "metricBindingsCreated": 1, "metricBindingsUpdated": 0, "metricBindingsUnchanged": 0
}

The *Received/Created/Updated/Unchanged counts let a sync job verify exactly what changed.

Validation error 400 (nothing written)

{
"message": "Topology import payload validation failed.",
"errors": [
{ "path": "edges[0]", "message": "Edge not allowed: a 'Host' cannot 'runs_on' a 'Component'." }
]
}

Common causes: unknown nodeType/edgeType; duplicate external IDs in one request; an edge or binding referencing an unknown node; invalid containment/hosting/dependency direction; metadata that is not a JSON object.

curl -X POST http://localhost:8080/v1/topology \
-H "Authorization: Bearer ${LUMETRY_API_TOKEN}" \
-H "Content-Type: application/json" \
-d @cmdb-topology.json

Console CRUD

Nodes

Method & pathPurpose
GET /api/topology/nodesList nodes.
GET /api/topology/nodes/{id}Get a node by integer id.
POST /api/topology/nodesCreate. Body: externalId, nodeType, displayName, environment (default production), optional ownerTeam, metadata (JSON string, default {}).
PUT /api/topology/nodes/{id}Update.
DELETE /api/topology/nodes/{id}Soft-delete the node and its active edges/bindings.

A returned node (TopologyNodeDto) includes id, externalId, nodeType, displayName, environment, ownerTeam, metadata, createdAt, updatedAt.

Tree browsing (lazy)

Method & pathPurpose
GET /api/topology/tree?nodeType=&environment=The containment forest. Filters optional; omitted filters return the full forest.
GET /api/topology/tree/children?parentId=&nodeType=&environment=One containment level for lazy expansion. Omitting parentId returns containment roots.

Each tree node reports hasChildren, outboundDependencyCount, and inboundDependencyCount so the UI can render expandable rows without loading everything. Dependency counts are indicators — runtime edges are not tree children.

Dependencies & edges

Method & pathPurpose
GET /api/topology/nodes/{id}/dependenciesThe runtime relationship edges for a node, surfaced on demand.
POST /api/topology/edgesCreate an edge. Body: sourceNodeId, targetNodeId, edgeType, optional metadata. Direction and containment are validated.
DELETE /api/topology/edges/{id}Soft-delete an edge.

Bindings

Method & pathPurpose
GET /api/topology/bindings?metricId={metricKey}Bindings for a metric.
POST /api/topology/bindingsBind a metric to a node. Body: metricId (metric key), nodeId, optional bindingType (default emits).

Bindings are what resolve a metric to a service/CI, populating the related-service/CI context on alerts and incidents.