Hierarchy (Read)
All hierarchy GET routes are available to any authenticated user (admin, engineer, or operator).
Networks
GET /api/v1/networks?limit=100&offset=0
List all networks. Supports pagination.
Query parameters:
limit (optional) — Max items to return (default 100, max 1000)
offset (optional) — Items to skip (default 0)
Response: 200 OK — Paginated envelope
{
"data": [
{
"id": "uuid",
"name": "Production",
"description": "Production network",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}
GET /api/v1/networks/{networkID}
Get a single network by ID.
Response: 200 OK (single network object)
Error: 404 Not Found — Network does not exist
GET /api/v1/networks/{networkID}/enrichment-summary
Get aggregated SNMP enrichment and L2 discovery health data for a single network. Used by the Network Enrichment Panel to display per-network capability cards.
Response: 200 OK
{
"network_id": "uuid",
"total_devices": 42,
"devices_with_snmp": 38,
"snmp_active": 35,
"snmp_stale": 2,
"snmp_errored": 1,
"snmp_disabled": 0,
"l2_neighbor_count": 120,
"l2_unresolved_count": 3,
"last_discovery_at": "2026-03-22T10:30:00Z",
"last_l2_enrichment_at": "2026-03-22T08:00:00Z"
}
| Field |
Type |
Description |
network_id |
string |
UUID of the network |
total_devices |
int |
Total devices in this network (via device_network_membership) |
devices_with_snmp |
int |
Devices that have an snmp_target row |
snmp_active |
int |
SNMP targets with status='active' |
snmp_stale |
int |
SNMP targets with status='stale' |
snmp_errored |
int |
SNMP targets with status='error' |
snmp_disabled |
int |
SNMP targets with enabled=false |
l2_neighbor_count |
int |
Total L2 neighbors discovered for devices in this network |
l2_unresolved_count |
int |
L2 neighbors not yet resolved to a known device |
last_discovery_at |
string? |
Most recent SNMP discovery timestamp (null if never run) |
last_l2_enrichment_at |
string? |
Most recent L2 enrichment timestamp (null if never run) |
Error: 500 Internal Server Error — Database query failure
Autonomous Systems
GET /api/v1/networks/{networkID}/autonomous-systems?limit=100&offset=0
List all autonomous systems within a network. Supports pagination.
Query parameters:
limit (optional) — Max items to return (default 100, max 1000)
offset (optional) — Items to skip (default 0)
Response: 200 OK — Paginated envelope
{
"data": [
{
"id": "uuid",
"network_id": "uuid",
"asn": 65000,
"name": "AS65000",
"description": "Primary AS",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}
GET /api/v1/networks/{networkID}/autonomous-systems/{asID}
Get a single AS by ID.
Response: 200 OK (single AS object)
Error: 404 Not Found
Routing Domains
GET /api/v1/networks/{networkID}/autonomous-systems/{asID}/routing-domains?limit=100&offset=0
List all routing domains within an AS. Supports pagination.
Query parameters:
limit (optional) — Max items to return (default 100, max 1000)
offset (optional) — Items to skip (default 0)
Response: 200 OK — Paginated envelope
{
"data": [
{
"id": "uuid",
"as_id": "uuid",
"name": "Global",
"description": "Global routing table",
"type": "global",
"rd": null,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}
GET /api/v1/networks/{networkID}/autonomous-systems/{asID}/routing-domains/{rdID}
Get a single routing domain by ID.
Response: 200 OK (single routing domain object)
Error: 404 Not Found
Protocol Instances
GET /api/v1/networks/{networkID}/autonomous-systems/{asID}/routing-domains/{rdID}/protocol-instances?limit=100&offset=0
List all protocol instances within a routing domain. Supports pagination.
Query parameters:
limit (optional) — Max items to return (default 100, max 1000)
offset (optional) — Items to skip (default 0)
Response: 200 OK — Paginated envelope
{
"data": [
{
"id": "uuid",
"routing_domain_id": "uuid",
"protocol": "ospfv2",
"process_id": "1",
"address_family": "ipv4",
"description": "Primary OSPF instance",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}
GET /api/v1/networks/{networkID}/autonomous-systems/{asID}/routing-domains/{rdID}/protocol-instances/{piID}
Get a single protocol instance by ID.
Response: 200 OK (single protocol instance object)
Error: 404 Not Found
Areas
GET /api/v1/networks/{networkID}/autonomous-systems/{asID}/routing-domains/{rdID}/protocol-instances/{piID}/areas?limit=100&offset=0
List all areas within a protocol instance. Supports pagination.
Query parameters:
limit (optional) — Max items to return (default 100, max 1000)
offset (optional) — Items to skip (default 0)
Response: 200 OK — Paginated envelope
{
"data": [
{
"id": "uuid",
"protocol_instance_id": "uuid",
"area_id": "0.0.0.0",
"area_type": "normal",
"name": "Area 0",
"description": "Backbone area",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}
GET /api/v1/networks/{networkID}/autonomous-systems/{asID}/routing-domains/{rdID}/protocol-instances/{piID}/areas/{areaID}
Get a single area by ID.
Response: 200 OK (single area object)
Error: 404 Not Found
Hierarchy Tree (Bulk Query)
GET /api/v1/hierarchy/tree
Returns the entire hierarchy tree in a single query (optimized for sidebar rendering).
Response: 200 OK
[
{
"network": { "id": "...", "name": "Production", ... },
"autonomous_systems": [
{
"as": { "id": "...", "asn": 65000, ... },
"routing_domains": [
{
"rd": { "id": "...", "name": "Global", ... },
"protocol_instances": [
{
"pi": { "id": "...", "protocol": "ospf", ... },
"areas": [
{ "id": "...", "area_id": "0.0.0.0", ... }
]
}
]
}
]
}
]
}
]
Each area object carries collectors (the area's own home recorders — collector_config rows whose area_id is this area) and covering_recorders (read-only: recorders homed in a different area that also publish topology for this one — e.g. an IS-IS multi-area SNMP crawler seeded in the backbone that feeds each L1 area, or the SNMP side of an area also watched over GRE). Home collectors and covering recorders both carry the optional verified-health fields verification_state, last_verified_at, verification_reason_code, lsdb_truncated, lsdb_lsa_count, and lsdb_truncated_at. verification_state is unknown, verified, pending, unreachable, or truncated. It is health/UI evidence only: a retained degraded recorder continues to suppress BGP-LS overlap until its retention lease ends or the operator disables/deletes it.
EIGRP home collectors and covering_recorders additionally carry optional
last_observed_at (RFC3339), read from their own AS/AF context's
collector_area_coverage.last_seen in the hierarchy response.
This is the last poll observing that context (debounced per recorder/area), not
the home recorder's last_data_at, a retention heartbeat, a complete route-table
walk or proof that all devices were reached. The sidebar labels it Last IPv6
observation (or IPv4), separately from recorder process status. It is omitted
for non-EIGRP sources, home recorders without a coverage row, ordinary collector
CRUD responses, and multi-area deletion-guard records. Older API
responses without it remain supported and render unavailable freshness.
An active IS-IS bootstrap parent additionally carries isis_bootstrap: { generation_id, phase, handoff_started_at?, desired_count, acked_count, areas[] }. Each area entry contains only orchestration identifiers, selected target, management source, acknowledgement, and retry timing. The object is derived from collector_state, sorted, and returned only when its embedded config version matches the collector row; raw state and credentials are never exposed. After handoff, transient status disappears and durable completion remains under collector.config.isis_bootstrap. Fully marked managed IS-IS child rows are read-only: update, toggle, and delete return 409. A successfully transferred child instead carries derived bootstrap_provisioned: true; it is operator-owned and supports normal CRUD while its bootstrap identity and provenance fields remain immutable.