Routes & Interfaces (Read)
All route and interface endpoints support multi-scope querying. In addition to area_id, you can pass pi_id (protocol instance), rd_id (routing domain), or network_id to query across all areas within that scope. The backend resolves the scope to a set of area IDs using the hierarchy. Exactly one scope parameter is required.
List Inter-Area Route Summary
GET /api/v1/routes/inter-area/summary?area_id={areaID}
GET /api/v1/routes/inter-area/summary?pi_id={piID}
GET /api/v1/routes/inter-area/summary?rd_id={rdID}
GET /api/v1/routes/inter-area/summary?network_id={networkID}
Paginated inter-area routes grouped by network prefix. Returns aggregate statistics per prefix for the summary/drill-down UI pattern.
Query parameters (mutually exclusive, one required):
area_id — UUID of the area
pi_id — UUID of the protocol instance (returns routes from all areas in the PI)
rd_id — UUID of the routing domain (returns routes from all areas in the RD)
network_id — UUID of the network (returns routes from all areas in the network)
Optional:
search — Prefix substring filter (e.g. 10.1.)
sort — Sort column (whitelisted). Default: network.
sort_dir — asc or desc (default asc)
limit — Page size (default 50, max 1000)
offset — Pagination offset
Response: 200 OK
{
"summaries": [
{
"network": "10.1.0.0/16",
"router_count": 3,
"min_metric": 10,
"max_metric": 30,
"area_count": 2
}
],
"total": 142
}
Error: 400 Bad Request — Missing scope parameter
List Inter-Area Routes
GET /api/v1/routes/inter-area?area_id={areaID}
GET /api/v1/routes/inter-area?pi_id={piID}
GET /api/v1/routes/inter-area?rd_id={rdID}
GET /api/v1/routes/inter-area?network_id={networkID}
List inter-area routes (Type 3 Summary-LSA) for a specific scope. When network is provided, returns paginated per-router detail for that prefix (drill-down mode with display_name enrichment). Without network, returns all routes (legacy behavior for time-travel).
Query parameters (mutually exclusive, one required):
area_id — UUID of the area
pi_id — UUID of the protocol instance (returns routes from all areas in the PI)
rd_id — UUID of the routing domain (returns routes from all areas in the RD)
network_id — UUID of the network (returns routes from all areas in the network)
Optional:
network — CIDR prefix filter for drill-down (e.g. 10.1.0.0/16). Enables paginated mode with display_name enrichment.
sort — Sort column (whitelisted). Default: network.
sort_dir — asc or desc (default asc)
limit — Page size (default 50, max 1000; only used with network)
offset — Pagination offset (only used with network)
at — RFC 3339 timestamp (e.g. 2026-02-22T10:00:00Z). When present, returns routes as they existed at that point in time (filters by first_seen <= at; last_seen is a refresh timestamp, not an end of validity — still-present rows count even when not re-confirmed since at). Uses legacy unpaginated path.
Response (with network): 200 OK
{
"routes": [
{
"id": "uuid",
"network": "10.1.0.0/16",
"adv_router": "10.0.0.2",
"device_id": "uuid",
"display_name": "rtr-core-01",
"metric": 20,
"area_id": "uuid",
"first_seen": "2026-02-17T10:00:00Z",
"last_seen": "2026-02-18T14:00:00Z"
}
],
"total": 3
}
Response (without network, legacy): 200 OK — flat JSON array of routes (no pagination envelope).
Error: 400 Bad Request — Missing scope parameter
List External Route Summary
External summary and detail/live-list envelopes add excluded_in_scope: the
number of stored Type-5 advertisements excluded by the current area-type guard
across the entire selected area scope, before search, exact-prefix filtering,
grouping and pagination. This counts advertisements, not unique prefixes or
routers, and is separate from total (eligible rows/groups matching the query).
The same number is supplied in X-Osprey-Excluded-External-Routes on nonempty
resolved scopes, including the legacy historical array response. A count failure
fails the request instead of returning a false zero. Counting adds one read-only
query per request; it uses a separate read from the route page, not an atomic
snapshot. No acquisition or background polling is added. Stored evidence remains
inspectable through GET /lsdb; its existing per-type truncation still applies.
GET /api/v1/routes/external/summary?area_id={areaID}
GET /api/v1/routes/external/summary?pi_id={piID}
GET /api/v1/routes/external/summary?rd_id={rdID}
GET /api/v1/routes/external/summary?network_id={networkID}
Paginated stored external-route advertisements grouped by
(network, metric_type, is_nssa, protocol_instance_id). asbr_count counts
distinct stored devices within each group, not independent default origins.
is_nssa separates Type 5 (E1/E2) and Type 7 (N1/N2). protocol_instance_id
and protocol_context identify network, AS, routing domain, protocol, process
and address family. Sorting by process sorts the context label; all summary
sorts append the full group key as a tie-breaker.
The defaults preset uses the exact server regex ^(0[.]0[.]0[.]0/0|::/0)$.
Exact-prefix detail includes all types/processes in the selected scope, with
PI identity/context and one row per stored area advertisement. These are
report-only joins over existing tables. Both report readers exclude Type 5
in stub, NSSA, totally_stub and totally_nssa areas. Collection and shared
routing readers are unchanged; no freshness or completeness claim follows.
Scope parameters (choose one):
area_ids — Comma-separated area UUIDs
area_id — UUID of the area
pi_id — UUID of the protocol instance
rd_id — UUID of the routing domain
network_id — UUID of the network
Optional:
search — Prefix filter
search_mode — text (default) or regex
sort — Sort column (whitelisted). Default: network.
sort_dir — asc or desc (default asc)
limit — Page size (default 100, max 10000)
offset — Pagination offset
Response: 200 OK
{
"data": [
{
"network": "0.0.0.0/0",
"metric_type": 2,
"is_nssa": false,
"protocol_instance_id": "uuid",
"protocol_context": "Example / AS 65001 / global / ospfv2 1 ipv4",
"asbr_count": 2,
"min_metric": 10,
"max_metric": 20,
"has_nssa": false,
"has_fwd_addr": false,
"first_seen": "2026-09-09T12:34:56Z",
"last_seen": "2026-09-10T09:00:00Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}
Error: 400 Bad Request — Missing scope parameter
List External Routes
GET /api/v1/routes/external?area_id={areaID}
GET /api/v1/routes/external?pi_id={piID}
GET /api/v1/routes/external?rd_id={rdID}
GET /api/v1/routes/external?network_id={networkID}
Lists stored Type 5/7 advertisements in scope. With network, the match is
exact CIDR text, not containment; returns paginated per-area rows, enriched
with display_name, area_label, protocol_instance_id and protocol_context.
The context includes network/AS/routing domain/protocol/process/AF. Detail includes
all types/processes for the prefix in the selected scope. Without network, the
live list is paginated; the historical reader returns the legacy flat array unless
with_exclusions=true requests {data,total,limit,offset,excluded_in_scope}.
That historical envelope remains unpaginated (limit=total, offset=0).
Both eligibility and exclusion counts use current area classification and the
existing first-seen cutoff; no deleted-row or historical-areatype reconstruction.
Query parameters (mutually exclusive, one required):
area_ids — Comma-separated area UUIDs
area_id — UUID of the area
pi_id — UUID of the protocol instance
rd_id — UUID of the routing domain
network_id — UUID of the network
Optional:
network — Exact CIDR prefix for drill-down (e.g. 0.0.0.0/0). Enables paginated mode with display_name enrichment.
sort — Sort column (whitelisted). Default: metric; detail has a stable UUID tie-breaker. process sorts the context label.
sort_dir — asc or desc (default asc)
limit — Page size (default 100, max 10000)
offset — Pagination offset
at — RFC 3339 timestamp (e.g. 2026-02-22T10:00:00Z). When present without network, returns retained routes whose first_seen predates that time (filters by first_seen <= at; last_seen is a refresh timestamp, not an end of validity — still-present rows count even when not re-confirmed since at). Uses the legacy unpaginated path. With network, the live reader takes precedence; the UI does not combine live drill-down with history.
Response (with network): 200 OK
{
"data": [
{
"id": "uuid",
"network": "0.0.0.0/0",
"adv_router": "10.0.0.5",
"device_id": "uuid",
"display_name": "rtr-edge-01",
"metric_type": 2,
"metric": 1,
"tag": 0,
"is_nssa": false,
"area_id": "uuid",
"area_label": "0.0.0.0",
"protocol_instance_id": "uuid",
"protocol_context": "Example / AS 65001 / global / ospfv2 1 ipv4",
"first_seen": "2026-02-17T10:00:00Z",
"last_seen": "2026-02-18T14:00:00Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}
Response (without network): live responses use the same data/total/limit/offset envelope, without drill-down enrichment. With at, the historical response is a flat JSON array (no pagination envelope); an empty resolved scope returns an empty paginated envelope before either reader runs.
Notes:
metric_type is 1 or 2. Display as E1/E2 for Type 5 and N1/N2 when is_nssa is true.
fwd_addr is omitted when the stored value is absent; otherwise it contains the stored IP address.
is_nssa is true for routes learned from Type 7 (NSSA-External) LSAs.
Error: 400 Bad Request — Missing scope parameter
List ASBR Entries
GET /api/v1/routes/asbr?area_id={areaID}
GET /api/v1/routes/asbr?pi_id={piID}
GET /api/v1/routes/asbr?rd_id={rdID}
GET /api/v1/routes/asbr?network_id={networkID}
List ASBR reachability entries (Type 4 Summary-LSA) for a specific scope.
Query parameters (mutually exclusive, one required):
area_id — UUID of the area
pi_id — UUID of the protocol instance
rd_id — UUID of the routing domain
network_id — UUID of the network
Optional:
at — RFC 3339 timestamp. When present, returns the as-of-T entry set from the snapshot validity windows (unpaginated array, like the sibling route reports; search/pagination apply to the live path only).
Response: 200 OK
[
{
"id": "uuid",
"asbr_id": "10.0.0.5",
"adv_router": "10.0.0.2",
"device_id": "uuid",
"metric": 10,
"area_id": "uuid",
"first_seen": "2026-02-17T10:00:00Z",
"last_seen": "2026-02-18T14:00:00Z"
}
]
Notes:
asbr_id is the router ID of the ASBR being advertised.
adv_router is the ABR that originates the Type 4 LSA to advertise ASBR reachability.
Error: 400 Bad Request — Missing scope parameter
List Device Interfaces
GET /api/v1/devices/{deviceID}/interfaces
List interfaces for a specific device. Interface data is extracted from Router-LSA P2P and transit link entries.
Response: 200 OK
[
{
"id": "uuid",
"device_id": "uuid",
"ip_address": "10.0.12.1",
"mask": "255.255.255.252",
"peer_id": "10.0.0.2",
"cost": 10,
"link_type": "p2p",
"first_seen": "2026-02-17T10:00:00Z",
"last_seen": "2026-02-18T14:00:00Z"
}
]
Notes:
peer_id is the peer router ID from the Router-LSA LinkID field.
link_type is the Router-LSA link type: "p2p", "transit", "stub", or "virtual".
- The response is the raw
store.Interface shape. Beyond the fields shown above, each entry may carry the following (all omitempty — present only when populated):
- Identity/scope:
area_id, if_index, source, peer_system_id (IS-IS peer system ID).
- IPv6 / dual-stack (IS-IS):
ipv6_address (string — the IPv6 address on the same ifIndex) and ipv6_prefix_len (integer — prefix length of ipv6_address, per RFC 4293 ipAddressPrefix).
- SNMP enrichment:
if_name, if_descr, if_alias, speed_mbps, if_mtu, dns_name.
- OSPF timers/config:
ospf_hello_interval, ospf_dead_interval, ospf_auth_type, ospf_network_type.
- IS-IS timers/config:
isis_hello_interval, isis_hold_time, isis_metric, isis_circuit_type, isis_level, isis_priority.
- This per-device endpoint returns interfaces unmerged, so it does not emit the
ip_address_v6 / mask_v6 merge-display fields — those appear only on the scoped GET /interfaces endpoint (below).
Error: 500 Internal Server Error — Database error
List Device Neighbors
These existing reads are included in the 1.4.4 OpenAPI reference. Ordinary authenticated operator, engineer and admin credentials are supported. Restricted read-only API keys receive 403; documentation inclusion does not change access.
GET /api/v1/devices/{deviceID}/neighbors
GET /api/v1/devices/{deviceID}/neighbors?area_id={areaID}
Reconstruct device neighbors from stored topology links. This is not a live neighbor-table read or a protocol state-machine report. Rows collapse parallel links to one neighbor per area; unresolved endpoints are omitted. The returned area_id is an area label (UUID fallback), and neighbor_id is a router ID. Interface details can be empty. Summary down counts every state other than up.
Path parameters:
deviceID (required) — UUID of the device
Query parameters:
area_id (optional) — Filter by area UUID or area label (e.g., "0.0.0.0"). When omitted, returns neighbors across all areas.
Response: 200 OK
{
"device_id": "uuid",
"router_id": "10.0.0.1",
"hostname": "router1",
"neighbors": [
{
"neighbor_id": "10.0.0.2",
"device_id": "uuid",
"hostname": "router2",
"state": "up",
"address": "10.1.1.2",
"local_address": "10.1.1.1",
"interface": "Gi0/0/1",
"cost": 10,
"reverse_cost": 10,
"link_type": "transit",
"area_id": "0.0.0.0",
"is_abr": false,
"is_asbr": false,
"first_seen": "2026-02-24T10:00:00Z",
"last_seen": "2026-02-24T12:00:00Z"
}
],
"summary": {
"total": 5,
"up": 4,
"down": 1
}
}
Notes:
neighbor_id is the OSPF router ID of the neighbor.
hostname is the neighbor's display name, resolved as Hostname → DNSName (sysName) fallback. May be empty if neither is known.
state is the adjacency state: "up" or "down".
address is the neighbor's interface IP on the shared link; local_address is this device's interface IP.
interface is the SNMP-enriched interface name on the neighbor (e.g., "Gi0/0/1").
cost is the metric from this device to the neighbor; reverse_cost is the metric in the opposite direction.
link_type is the Router-LSA link type: "p2p", "transit", "stub", or "virtual".
area_id is the OSPF area label (dotted notation) for this adjacency.
is_abr / is_asbr indicate whether the neighbor has the ABR or ASBR flag set.
summary provides aggregate counts of total, up, and down neighbors.
Error responses:
400 Bad Request — Invalid device ID or invalid area_id parameter
404 Not Found — Device does not exist
Get Device EIGRP
GET /api/v1/devices/{deviceID}/eigrp
A device's EIGRP adjacencies and EIGRP-enabled interfaces, discovered passively via CISCO-EIGRP-MIB (SNMP). All-role read. An unknown device yields empty lists, not an error.
Path parameters:
deviceID (required) — UUID of the device
Response: 200 OK
{
"neighbors": [
{
"id": "uuid",
"device_id": "uuid",
"peer_addr": "10.0.12.1",
"address_family": "ipv4",
"as_number": 100,
"vrf_name": "default",
"local_ifindex": 2,
"local_if_name": "Et0/1",
"remote_device_id": null,
"remote_hostname": "",
"hold_time": 14,
"srtt_ms": 1600,
"rto_ms": 5000,
"uptime": "01:00:13",
"source": "snmp",
"first_seen": "2026-07-20T10:00:00Z",
"last_seen": "2026-07-20T12:00:00Z"
}
],
"interfaces": [
{ "if_index": 2, "name": "Et0/1", "hello_interval": 5, "peer_count": 1, "mean_srtt": 1600 }
]
}
Notes:
peer_addr is the neighbor address; IPv6 neighbors are link-local (fe80::) and not globally routable.
as_number is the EIGRP process AS, not the BGP-ASN hierarchy level. The same peer can appear once per (VRF, AF, AS).
remote_device_id / remote_hostname are resolved from the local port (cEigrpPeerIfIndex) + the L2 adjacency on it. Null/empty when unresolved (no L2 adjacency, or a multi-access port with ambiguous remotes) — honest degradation.
neighbors and interfaces always encode as [] when empty.
Error responses:
400 Bad Request — Missing device ID
Get Network EIGRP Topology
GET /api/v1/networks/{networkID}/eigrp/topology
Every EIGRP neighbor whose device belongs to the network, for the topology overlay / EIGRP Topology Reports panel. The frontend derives undirected adjacency edges from the (device_id, remote_device_id) pairs (an edge is bidirectional when both endpoints observe each other, a half-adjacency otherwise). All-role read.
Path parameters:
networkID (required) — UUID of the network
Response: 200 OK
{
"neighbors": [
{
"id": "uuid",
"device_id": "uuid",
"remote_device_id": "uuid",
"peer_addr": "10.0.12.2",
"address_family": "ipv4",
"as_number": 100,
"vrf_name": "default",
"device_hostname": "r1",
"remote_hostname": "r2"
}
]
}
Notes:
- Scoping mirrors the L2 topology: a device is in the network via
device_network_membership or the routing hierarchy.
neighbors always encodes as [] when empty.
Error responses:
400 Bad Request — Missing network ID
Get EIGRP Observed Path
GET /api/v1/eigrp/path?source_device_id={deviceID}&dest_ip={address}
GET /api/v1/eigrp/path?source_device_id={deviceID}&dest_ip={address}&at={RFC3339}
Reconstructs the EIGRP forwarding path from a source device toward a destination address by chaining the observed next-hops — not by running SPF. EIGRP's composite metric mixes min(bandwidth) with summed delay, so it is not expressible as one additive edge cost, and its components are not readable over SNMP. The routers have already run DUAL, so Osprey reads the resulting distributed FIB (cEigrpTopoTable) instead of modelling it. All-role read.
Query parameters:
source_device_id (required) — UUID of the starting device
dest_ip (required) — destination address (IPv4 or IPv6)
vrf (optional) — the routing context the walk lives in (default: the global table). A chain never crosses VRFs; a destination that continues only in another table terminates with context_boundary (§64)
at (optional) — historical sample time. Every visited and decision-relevant
device is resolved from eigrp_route_snapshot; a gap terminates with
history_unavailable and never borrows live routes. Future times are invalid.
Response: 200 OK
{
"hops": [
{ "device_id": "uuid-a", "route": { "dest_prefix": "10.0.99.0/24", "next_hop": "10.0.12.2", "fdistance": 128256, "route_origin": "Internal" }, "next_device_id": "uuid-b" },
{ "device_id": "uuid-b", "route": { "dest_prefix": "10.0.99.0/24", "route_origin": "Connected" } }
],
"devices": ["uuid-a", "uuid-b"],
"complete": true,
"terminated": "delivered"
}
Without at, the existing live response shape is unchanged. With at, the
response also contains eigrp_history and uses a historical route DTO that
intentionally has no live row id, source, or first/last/create/update
timestamps. Coverage is complete, partial, or unavailable; temporal
evidence is sampled, bracketed, carried_forward, or unavailable.
Notes:
- Each hop matches the destination by longest prefix among the walk's own VRF's rows, skipping rows DUAL holds with zero successors (not installed — §61). Equal specificity breaks on AD class first (connected < internal 90 < external 170 — the cross-process rule, §64), then the lower feasible distance, then the lower AS number (deterministic).
complete is true only when the walk ended on a connected route — the destination was genuinely reached. Every other outcome is a partial result, honestly labelled by terminated: no_route, next_hop_unknown (the next-hop was never resolved to a device — typically no L2 adjacency on that port, and IPv6 next-hops are link-local so they depend on L2 coverage), loop, max_hops (32), invalid_destination, route_unreachable (the device knows the prefix but DUAL has no feasible successor — §61), context_boundary (the destination is only routable in a different VRF — §64).
- Route rows carry the DUAL distance triplet where collected:
fdistance (the feasibility threshold — a historical minimum per RFC 7868 §§2.2/3.3, NULL when saturated/no-successor), computed_distance (the current distance of the stored via, col 15) and reported_distance (that via's reported distance, col 16).
- The walk is loop-safe (visited set) and hop-bounded.
- The same engine backs the main path endpoint: a
GET /topology/path query whose scope is EIGRP falls back to this chain when SPF finds nothing, and stitched cross-domain paths use it for EIGRP segments. Such a segment carries total_cost: -1 (EIGRP costs never sum) and therefore does not take part in cost-based border selection.
- In a live IPv6 cross-domain path, the final EIGRP segment uses the IPv6 destination address already selected for that direction, rather than the device's IPv4 router ID. Missing IPv6 route evidence leaves the segment opaque; it does not select IPv4 routes instead. If the chain reaches the destination subnet on another device, the stitched
caveat explicitly says that the final hop to the selected device is unverified, and the explanation names the actual last device. No final hop is invented. Historical queries, simulation, source/middle segments and device/IPv4 questions retain their existing target semantics. This correction does not establish that every stored IPv6 EIGRP candidate is an installed next hop.
- Through
GET /topology/path, each chained hop pair also resolves to its real link row (link_id, area_id; a dual-stack pair picks the area matching the destination's address family, ties break on the lowest link ID) and gains ingress/egress interface enrichment like any SPF hop — this is what lets the canvas draw the path overlay on the actual edges. Per-hop cost stays a placeholder (0) and is not rendered. The bare GET /eigrp/path endpoint returns the raw device chain without link resolution.
- Installed alternatives: the topology table exposes one candidate per destination. Retained
alt_next_hops and installed come from the IPv4 routing table or, for supported global IPv6 contexts, the IPv6 routing table with interface-scoped neighbor matching. A complete chain can carry variants (this endpoint) / ecmp_paths (GET /topology/path, capped at 4). These are observed installed alternatives; membership alone does not prove equal cost or traffic share. An IPv6 hop switched to another member omits the original candidate's interface name and per-via computed/reported distances. Feasible distance remains the destination's historical value, not a measured cost for the selected member. Unsupported, ambiguous or failed IPv6 observations retain the existing missing-evidence warning; older live sets may survive a failed poll.
Error responses:
400 Bad Request — Missing parameters, malformed timestamp, or future at
500 Internal Server Error — Snapshot read, decode, or integrity failure
SPF tree and EIGRP. GET /api/v1/topology/spf-tree refuses an EIGRP area with 400. EIGRP runs DUAL, not SPF, and its links are stored with cost 0 because the composite metric is a property of a whole path rather than of an edge — rendering a Dijkstra tree over them would produce a tidy all-zero result that looks authoritative and means nothing. Use the observed path endpoint above instead. For the same reason EIGRP areas are excluded from the shared per-area graph loader, so path, RIB and simulation never traverse a zero-cost EIGRP segment (which would otherwise win every cheapest-path comparison).
EIGRP installation limits: GET /eigrp/path returns an optional caveat
when a followed primary or displayed alternate next hop lacks membership in
the retained installed next-hop set. This applies in live and historical mode.
complete: true and terminated: delivered still mean that the candidate
walk reached an observed connected prefix, not that packet delivery was tested.
The general path response carries the same caveat. On cross-domain paths,
domain_segments[].confidence is capped at inferred for an unconfirmed
EIGRP source exit and subsequent domains; an unconfirmed primary segment also
limits its downstream domains. Segment note explains this dependency and
the border-selection explanation names an unconfirmed source choice. Existing
opaque segments remain opaque. The selected hops, metrics and AS path do not
change. Historical forwarded IPv6/VRF rows with acquisition not_applicable
contribute unavailable rather than not-applicable eigrp_history.rib_ecmp.
Membership describes retained evidence, not current freshness. Missing evidence
does not mean no route, and FD/CD equality or inequality never substitutes
for installed next-hop membership.
List Interfaces by Scope
GET /api/v1/interfaces?area_id={areaID}
GET /api/v1/interfaces?pi_id={piID}
GET /api/v1/interfaces?rd_id={rdID}
GET /api/v1/interfaces?network_id={networkID}
List all interfaces for devices in a specific scope. Interface data is extracted from Router-LSA P2P and transit link entries. When OSPFv2 and OSPFv3 interfaces share the same (device_id, if_name, area_label), they are merged into a single entry with both IPv4 and IPv6 addresses.
Query parameters (mutually exclusive, one required):
area_id — UUID of the area
pi_id — UUID of the protocol instance
rd_id — UUID of the routing domain
network_id — UUID of the network
Optional:
at — RFC 3339 timestamp (e.g. 2026-02-22T10:00:00Z). When present, returns interfaces as they existed at that point in time (filters by first_seen <= at; last_seen is a refresh timestamp, not an end of validity — still-present rows count even when not re-confirmed since at).
Response: 200 OK
[
{
"id": "uuid",
"device_id": "uuid",
"ip_address": "10.0.12.1",
"mask": "255.255.255.252",
"ip_address_v6": "2001:db8::1",
"mask_v6": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc",
"peer_id": "10.0.0.2",
"cost": 10,
"link_type": "p2p",
"first_seen": "2026-02-17T10:00:00Z",
"last_seen": "2026-02-18T14:00:00Z"
}
]
Notes:
- Returns all interfaces for all devices in the specified scope.
- Each entry embeds the full
store.Interface shape (same fields as the per-device endpoint above, including the omitempty ipv6_address, ipv6_prefix_len, if_name, if_descr, if_alias, speed_mbps, if_mtu, dns_name, ospf_*, and isis_* fields), plus the two merge-display fields below.
ip_address_v6 and mask_v6 are present when the entry has an IPv6 address to display — either an OSPFv2/OSPFv3 interface pair merged into one entry, or a single dual-stack IS-IS row that carries both an IPv4 and an IPv6 address on the same ifIndex. Single-protocol IPv4-only interfaces omit these two fields.
- The form of
mask_v6 depends on the source: for a merged OSPFv3 interface it is the full IPv6 netmask (e.g. "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc", copied from the v3 interface's mask); for a dual-stack IS-IS interface it is instead a "/NN" prefix-length string (e.g. "/64", rendered from ipv6_prefix_len via v6PrefixMask).
Error: 400 Bad Request — Missing scope parameter
List Stub Networks
GET /api/v1/stub-networks?area_id={areaID}
GET /api/v1/stub-networks?pi_id={piID}
GET /api/v1/stub-networks?rd_id={rdID}
GET /api/v1/stub-networks?network_id={networkID}
List stub networks (host routes, loopbacks, attached networks with no adjacency) for a specific scope. Supports server-side pagination and search for live mode. Time-travel mode (at param) uses the legacy unpaginated path.
Query parameters (mutually exclusive, one required):
area_id — UUID of the area
pi_id — UUID of the protocol instance
rd_id — UUID of the routing domain
network_id — UUID of the network
Optional:
search — Prefix or device name substring filter
sort — Sort column (whitelisted). Default: network.
sort_dir — asc or desc (default asc)
limit — Page size (default 50, max 1000)
offset — Pagination offset
at — RFC 3339 timestamp (e.g. 2026-02-22T10:00:00Z). When present, returns stub networks as they existed at that point in time (filters by first_seen <= at; last_seen is a refresh timestamp, not an end of validity — still-present rows count even when not re-confirmed since at). Bypasses pagination (returns flat array).
Response (paginated, no at): 200 OK
{
"stubs": [
{
"id": "uuid",
"network": "192.168.1.0/24",
"device_id": "uuid",
"display_name": "rtr-core-01",
"cost": 1,
"area_id": "uuid",
"first_seen": "2026-02-17T10:00:00Z",
"last_seen": "2026-02-18T14:00:00Z"
}
],
"total": 1204
}
Response (legacy, with at): 200 OK — flat JSON array of stub networks (no display_name, no pagination envelope).
Notes:
display_name is resolved server-side via the display.device_name_mode system setting (hostname, router_id, or dns).
Error: 400 Bad Request — Missing scope parameter