Reports
Get Topology Change Summary
GET /api/v1/reports/change-summary?area_id=<uuid>&period=24h
GET /api/v1/reports/change-summary?pi_id=<uuid>&period=7d
GET /api/v1/reports/change-summary?rd_id=<uuid>&period=30d
GET /api/v1/reports/change-summary?network_id=<uuid>&period=1h
Aggregates topology events by type over the specified period. Groups event type counts into structured categories (devices, links, stubs) with raw counts preserved.
Query parameters:
- Scope:
area_id, area_ids, pi_id, rd_id, or network_id (same as other endpoints)
period — Time window: 1h, 6h, 24h (default), 7d, 30d
Response: 200 OK
{
"period": {
"from": "2026-02-23T08:00:00Z",
"to": "2026-02-24T08:00:00Z"
},
"devices": { "added": 2, "removed": 1, "changed": 3 },
"links": { "added": 5, "removed": 2, "state_changes": 8, "cost_changes": 1 },
"stubs": { "added": 4, "removed": 1, "changed": 0 },
"total_events": 27,
"raw_counts": {
"device_added": 2,
"device_removed": 1,
"device_flags_changed": 3,
"link_added": 5,
"link_removed": 2,
"link_state_changed": 8,
"link_cost_changed": 1,
"stub_added": 4,
"stub_removed": 1
}
}
Error responses:
400 Bad Request -- Missing scope parameter
Get Congestion Trend Report
GET /api/v1/reports/congestion?area_id=<uuid>
GET /api/v1/reports/congestion?pi_id=<uuid>
GET /api/v1/reports/congestion?rd_id=<uuid>
GET /api/v1/reports/congestion?network_id=<uuid>
Identifies interfaces that have consistently exceeded a utilization threshold over a configurable time period. Uses hourly bucketed data from the utilization_history table (populated by the SNMP poller). Returns hotspots sorted by hours above threshold, with per-hour history for sparkline rendering.
Query parameters:
- Scope (mutually exclusive, one required):
area_id, area_ids, pi_id, rd_id, or network_id
threshold — Utilization percentage threshold (default 80, range 1-100)
period — Time window: 1h, 6h, 24h, 7d (default), 30d
Response: 200 OK
{
"hotspots": [
{
"interface_id": "uuid",
"device_id": "uuid",
"router_id": "10.0.0.1",
"hostname": "rtr-core-01",
"if_name": "Gi0/0/0",
"speed_mbps": 1000,
"max_utilization": 97.3,
"avg_utilization": 82.1,
"hours_above_threshold": 42,
"total_hours": 168,
"trend": "increasing",
"history": [
{ "bucket_time": "2026-02-17T00:00:00Z", "max_util": 85.2 }
]
}
],
"summary": {
"interfaces_checked": 64,
"above_threshold": 3,
"threshold": 80,
"period": "7d"
}
}
Notes:
trend is one of "increasing", "stable", or "decreasing", computed by comparing the first-half and second-half average utilization of the period.
history contains one entry per hour for sparkline rendering in the frontend.
- Only interfaces with at least one hourly bucket exceeding the threshold are returned as hotspots.
Auth: Required (all roles).
Error responses:
400 Bad Request -- Missing scope parameter
500 Internal Server Error -- Database error
Get LSDB (Link-State Database)
GET /api/v1/lsdb?area_id=<uuid>
GET /api/v1/lsdb?pi_id=<uuid>
GET /api/v1/lsdb?rd_id=<uuid>
GET /api/v1/lsdb?network_id=<uuid>
Reconstructs the OSPF LSDB from existing topology tables (devices, interfaces, stub_networks, inter_area_route, asbr_entry, external_route). Returns summary counts and per-type LSA arrays.
Type-5/7 arrays retain stored advertisements excluded from ordinary route reports. Entries add area_id, current area_type, area_type_source (operator_declared for totally_stub/totally_nssa, otherwise unknown), optional reported_by_collector_id (existing last-writer attribution), and optional routing_exclusion: "type5_area_type_conflict". Absence of that reason only means the area filter permits the row, not proof of routability. Historical rows use the current area classification; deleted advertisements and SNMP rows discarded before storage cannot be reconstructed. Counts and truncation include excluded stored rows.
Query parameters:
- Scope (mutually exclusive, one required):
area_id, pi_id, rd_id, or network_id
lsa_limit — Max LSAs returned per type (default 500, max 5000). When a type is truncated, the summary includes *_full fields with the actual total count (e.g. summary_lsas_full: 2800 when summary_lsas: 500).
Response: 200 OK
{
"summary": {
"router_lsas": 12,
"network_lsas": 4,
"summary_lsas": 28,
"asbr_summaries": 2,
"external_lsas": 15,
"nssa_externals": 0,
"total": 61
},
"router_lsas": [
{
"link_state_id": "10.0.0.1",
"adv_router": "10.0.0.1",
"hostname": "rtr-core-01",
"is_abr": true,
"is_asbr": false,
"link_count": 4,
"links": [
{ "type": "point_to_point", "link_id": "10.0.0.2", "link_data": "10.1.0.1", "metric": 10 },
{ "type": "stub", "link_id": "192.168.1.0", "link_data": "255.255.255.0", "metric": 1 }
],
"header": {
"seq_number": 2147483648,
"ls_age": 45,
"checksum": 12345,
"options": 34,
"updated_at": "2026-03-05T14:23:46.456Z"
}
}
],
"network_lsas": [
{
"link_state_id": "10.1.0.1",
"adv_router": "10.0.0.1",
"network_mask": "255.255.255.252",
"attached_routers": ["10.0.0.1", "10.0.0.2"],
"header": {
"seq_number": 2147483648,
"ls_age": 120,
"checksum": 56789,
"options": 34,
"updated_at": "2026-03-05T14:20:15.123Z"
}
}
],
"summary_lsas": [
{
"link_state_id": "192.0.2.0",
"adv_router": "10.0.0.1",
"network_mask": "255.255.255.0",
"metric": 100
}
],
"asbr_summaries": [
{
"link_state_id": "10.0.0.5",
"adv_router": "10.0.0.1",
"metric": 50
}
],
"external_lsas": [
{
"link_state_id": "0.0.0.0",
"adv_router": "10.0.0.5",
"network_mask": "0.0.0.0",
"metric": 1,
"metric_type": "E2",
"forward_address": "0.0.0.0",
"tag": 0
}
],
"nssa_externals": []
}
Notes:
- Each LSA entry optionally includes a
header field (when live LSDB data is available) with fields: seq_number, ls_age, checksum, options, updated_at.
- Router-LSA links are derived from the interface and link tables. Network-LSA attached routers are derived from transit link endpoints.
- LSA headers (seq_number, ls_age, checksum, options) are sourced from the
lsdb_header table, which is populated by the engine from LSA update events. If the engine has not yet received headers for an LSA, the header field is omitted.
Get IS-IS LSDB (Link-State PDU Database)
GET /api/v1/isis-lsdb?area_id=<uuid>
Returns IS-IS LSP headers from the isis_lsp_header table for the IS-IS LSDB browser. Enriched with device hostnames resolved from system_id.
Query parameters:
area_id (required) — Area UUID (IS-IS level)
Response: 200 OK
{
"lsp_count": 3,
"lsps": [
{
"lsp_id": "0100.0000.0001.00-00",
"system_id": "0100.0000.0001",
"pseudonode_id": 0,
"fragment": 0,
"seq_number": 42,
"remaining_lifetime": 1100,
"checksum": 12345,
"overload_bit": false,
"attached_bit": false,
"is_type_bits": 3,
"pdu_length": 350,
"first_seen": "2026-03-15T10:00:00Z",
"updated_at": "2026-03-15T14:30:00Z",
"hostname": "rtr-core-01"
}
]
}
Notes:
- LSP ID format:
<system_id>.<pseudonode_id hex>-<fragment hex> (e.g. 0100.0000.0001.00-00)
- Pseudonode LSPs (pseudonode_id > 0) represent DIS-originated pseudonode LSPs on broadcast circuits
is_type_bits: 1 = L1 only, 2 = L2 only, 3 = L1/L2
- Hostname resolved from device table via system_id match
- All LSP header fields are flat on each entry — unlike the OSPF
/lsdb endpoint, IS-IS LSP entries have no nested header object.
seq_number — LSP sequence number (32-bit). checksum — LSP checksum (16-bit, ISO 10589 Fletcher checksum).
remaining_lifetime — seconds until the LSP expires; per ISO 10589 it counts down from the originator's maximum lifetime (default 1200s) toward 0 (contrast OSPF's LS Age, which counts up). There is no ls_age or options field.
overload_bit — LSP Overload (OL) bit: the originator requests that it not be used for transit. attached_bit — Attached (ATT) bit: an L1/L2 router signalling L1-only routers that it can reach other areas. attached_bit is written from the wire, and only from a level-1 LSP number zero (ISO 10589 §9.8): the same octet in a level-2 LSP or a later fragment is not the attach signal, and within it only the default metric drives level-1 default routing. A false therefore means "no attachment observed", never "the router declared itself unattached" — it is also what you get wherever no level-1 LSP has been recorded. Before 2026-09-16 the value was decoded and then dropped before reaching storage, so every row read false regardless of what the router advertised. overload_bit was unaffected throughout.
pdu_length (omitempty) — total LSP PDU length in bytes, when known. first_seen / updated_at — RFC 3339 timestamps for first observation and last update.
Auth: Required (all roles).
Error responses:
400 Bad Request -- Missing scope parameter
500 Internal Server Error -- Database error