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:

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:

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:

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:

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:

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.