Base URL: http://<host>:9090
All /api/* endpoints (except health and auth) require authentication via the mnm_token cookie.
Authenticate with the admin password.
Request:
{"password": "your-admin-password"}Response: 200 OK with Set-Cookie: mnm_token=...
{"status": "ok"}Check if the current session is authenticated.
Response:
{"authenticated": true}Clear the session cookie.
No authentication required.
Response:
{"status": "ok"}Returns health status of all MNM containers on the mnm-network.
Response:
{
"containers": [
{
"name": "mnm-nautobot",
"status": "running",
"health": "healthy",
"image": "mnm-nautobot:latest",
"ports": ["8443->8080/tcp"]
}
]
}Start a network sweep.
Request:
{
"cidr_ranges": ["192.0.2.0/24"],
"location_id": "uuid",
"secrets_group_id": "uuid",
"snmp_community": "public",
"auto_discover_hops": 0
}auto_discover_hops (optional, default 0): after onboarding a network device, walk its LLDP neighbors up to this many hops deep. 0 = disabled.
Response: 200 OK
{"status": "started"}Poll sweep progress. Returns per-host enriched data.
Response:
{
"running": true,
"hosts": {
"192.0.2.1": {
"ip": "192.0.2.1",
"status": "known",
"ports_open": [22, 161, 830],
"mac_address": "aa:bb:cc:dd:ee:ff",
"mac_vendor": "Juniper Networks",
"dns_name": "firewall-01.example.com",
"snmp": {"sysName": "firewall-01", "sysDescr": "..."},
"classification": "network_device",
"first_seen": "2026-04-05T14:30:00Z",
"last_seen": "2026-04-06T02:00:00Z"
}
},
"summary": null
}Returns LLDP neighbors not matching known devices.
Response:
{
"neighbors": [
{
"neighbor_name": "ap-lobby-01",
"connected_to": "ge-0/0/5 (core-switch-01)"
}
]
}Onboard a single device (from LLDP advisory).
Request:
{
"ip": "192.0.2.50",
"location_id": "uuid",
"secrets_group_id": "uuid"
}Returns configured sweep schedules.
Save a sweep schedule.
Request:
{
"cidr_ranges": ["192.0.2.0/24"],
"location_id": "uuid",
"secrets_group_id": "uuid",
"interval_hours": 24
}Returns all collected endpoint records. Supports query parameters: ?vlan=100, ?switch=core-switch-01, ?mac_vendor=Apple, ?source=infrastructure
Returns summary stats: total endpoints, VLANs active, vendors seen, last collection time.
Response:
{
"total_endpoints": 147,
"vlans_active": 12,
"vendors_seen": 45,
"switches": 2,
"last_collection": "2026-04-06T14:00:00Z",
"running": false
}Manually trigger an endpoint collection run.
Nodes are onboarded infrastructure devices that MNM authenticates to and actively polls.
List all onboarded nodes with poll health status.
Response:
{
"nodes": [
{
"name": "core-switch-01",
"id": "uuid",
"platform": "junos",
"primary_ip": "198.51.100.1/32",
"role": "Network Device",
"location": "Main Site",
"health": "green",
"health_label": "All polls healthy",
"last_polled": "2026-04-09T22:05:00Z",
"jobs": {
"arp": {"last_success": "...", "interval_sec": 300, "enabled": true},
"mac": {"last_success": "...", "interval_sec": 300, "enabled": true}
},
"interface_count": null,
"nautobot_url": "..."
}
]
}Returns details for a single node including poll status and Nautobot device data.
Returns MAC addresses belonging to onboarded nodes (used to filter endpoints page).
Response:
{"macs": ["AA:BB:CC:DD:EE:FF", "11:22:33:44:55:66"]}ARP table for a specific node. Query params: ip, mac.
MAC address table for a specific node. Query params: mac, interface, vlan.
LLDP neighbors for a specific node.
Forwarding table (FIB) entries for a specific node. Populated from SNMP route data. Query param: prefix.
Contextual network investigation. Auto-detects query type and returns categorized results. Accepts any MAC format (colon, hyphen, Cisco dot, bare hex) and normalizes internally.
Query params:
q(required) — MAC address, IP, CIDR prefix, or hostname textnode(optional) — filter results to a specific nodevlan(optional) — filter to a specific VLAN (MAC search only)type(optional) — force query type:mac,ip,prefix,text(auto-detected if omitted)
MAC search response:
{
"query": "aa:bb:cc:dd:ee:ff",
"query_type": "mac",
"results": {
"arp_hits": [{"node_name": "...", "ip": "198.51.100.10", "mac": "AA:BB:CC:DD:EE:FF", "interface": "ge-0/0/5"}],
"mac_hits": [{"node_name": "...", "mac": "AA:BB:CC:DD:EE:FF", "interface": "ge-0/0/5", "vlan": 100}],
"endpoint": {"mac": "AA:BB:CC:DD:EE:FF", "ip": "198.51.100.10", "hostname": "..."},
"location": {"switch": "core-switch-01", "interface": "ge-0/0/5", "vlan": 100, "description": "Connected to core-switch-01 port ge-0/0/5 in VLAN 100"},
"vm_host": {"name": "web-server-01", "vmid": 100, "node": "pve1", "status": "running", "type": "qemu"}
}
}IP search response:
{
"query": "198.51.100.1",
"query_type": "ip",
"results": {
"arp_hits": [{"node_name": "...", "ip": "198.51.100.1", "mac": "...", "interface": "..."}],
"routes": [{"node_name": "...", "prefix": "198.51.100.0/24", "next_hop": "...", "protocol": "ospf"}],
"fib": [{"node_name": "...", "prefix": "198.51.100.0/24", "next_hop": "...", "interface": "ge-0/0/0"}],
"endpoints": [{"mac": "...", "ip": "198.51.100.1", "hostname": "..."}]
}
}Prefix search response includes routes, fib, gateways, and arp_hits (ARP entries within subnet).
Text search response includes lldp (matching system names) and endpoints (matching hostnames).
Returns all devices from Nautobot (raw Nautobot API proxy, unfiltered).
Returns a single device from Nautobot.
Returns available credential sets.
Returns available locations.
Returns controller configuration.
Update controller configuration (merge).
# Login
curl -c cookies.txt -X POST http://localhost:9090/api/auth/login \
-H "Content-Type: application/json" \
-d '{"password":"test123"}'
# Check status
curl -b cookies.txt http://localhost:9090/api/status
# Start sweep
curl -b cookies.txt -X POST http://localhost:9090/api/discover/sweep \
-H "Content-Type: application/json" \
-d '{"cidr_ranges":["192.0.2.0/29"],"location_id":"uuid","secrets_group_id":"uuid","snmp_community":"public"}'
# Poll progress
curl -b cookies.txt http://localhost:9090/api/discover/statusConsolidated view of all background tasks: sweep scheduler, modular poller, Proxmox collector, database prune, and legacy endpoint collector.
Response:
{
"jobs": [
{
"id": "sweep",
"name": "Sweep Scheduler",
"status": "idle",
"running": false,
"schedule_interval": "1h",
"last_run": "2026-04-09T22:10:00Z",
"duration_seconds": 285.3,
"summary": {"total": 254, "alive": 10, "known": 3},
"enabled": true
}
]
}Re-run the first saved sweep schedule. Used by the Jobs page "Run Now" button.
Response: 200 OK
{"status": "started", "cidr_ranges": ["198.51.100.0/24"]}Per-device, per-job-type collection tracking. Replaces the monolithic endpoint collector.
All devices, all job types, grouped by device.
Response:
{
"devices": [
{
"device_name": "core-switch-01",
"jobs": {
"arp": {"last_success": "2026-04-09T22:05:00Z", "interval_sec": 300, "enabled": true},
"mac": {"last_success": "2026-04-09T22:05:06Z", "interval_sec": 300, "enabled": true},
"dhcp": {"last_success": null, "interval_sec": 600, "enabled": true},
"lldp": {"last_success": "2026-04-09T21:30:00Z", "interval_sec": 3600, "enabled": true}
}
}
]
}Single device, all job types.
Trigger immediate poll of all enabled job types for a device. Returns 202 Accepted.
Trigger a single job type (arp, mac, dhcp, lldp, routes, or bgp). Returns 202 Accepted.
Update interval or enabled flag for a specific device/job type.
Request:
{"interval_sec": 600, "enabled": false}Response: Updated poll row.
Routing table data collected from onboarded nodes via NAPALM. Stored in the controller database (Nautobot has no native routing model).
Query collected routes with optional filters.
Query params: node_name, vrf, protocol, prefix (substring search)
Response:
{
"routes": [
{
"id": 1,
"node_name": "core-switch-01",
"prefix": "198.51.100.0/24",
"next_hop": "198.51.100.1",
"protocol": "ospf",
"vrf": "default",
"metric": 10,
"preference": 110,
"outgoing_interface": "ge-0/0/0",
"active": true,
"collected_at": "2026-04-10T12:00:00Z"
}
],
"count": 1
}All routes for a specific node. Query params: vrf, protocol.
Routes with next-hops that don't match any known IP in endpoint data or Nautobot IPAM. These are discovery candidates.
Response:
{
"advisories": [
{
"node_name": "core-switch-01",
"prefix": "203.0.113.0/24",
"next_hop": "198.51.100.254",
"protocol": "static",
"vrf": "default"
}
],
"count": 1
}BGP neighbor state collected from onboarded nodes via NAPALM.
Query collected BGP neighbors with optional filters.
Query params: node_name, state, vrf
Response:
{
"neighbors": [
{
"id": 1,
"node_name": "core-router-01",
"neighbor_ip": "198.51.100.2",
"remote_asn": 65001,
"local_asn": 65000,
"state": "Established",
"prefixes_received": 150,
"prefixes_sent": 75,
"uptime_seconds": 86400,
"vrf": "default",
"address_family": "ipv4 unicast",
"collected_at": "2026-04-10T12:00:00Z"
}
],
"count": 1
}All BGP neighbors for a specific node. Query params: vrf.
Manually trigger hop-limited auto-discovery from a specific node.
Request:
{
"node_name": "core-switch-01",
"max_hops": 2,
"location_id": "uuid",
"secrets_group_id": "uuid",
"snmp_community": "public"
}Response:
{
"seed_node": "core-switch-01",
"max_hops": 2,
"attempted": 3,
"succeeded": 2,
"failed": 1,
"skipped": 0,
"nodes": [
{"name": "idf-switch-01", "ip": "198.51.100.10", "status": "succeeded", "hop_depth": 1, "parent": "core-switch-01"},
{"name": "idf-switch-02", "ip": "198.51.100.11", "status": "succeeded", "hop_depth": 1, "parent": "core-switch-01"},
{"name": "ap-closet-01", "ip": "198.51.100.20", "status": "failed", "hop_depth": 2, "parent": "idf-switch-01"}
]
}Past auto-discovery run summaries.
Nodes auto-discovered in the last N hours. Query param: hours (default 24). Used by the dashboard advisory card.
All tracked onboarding job states.
Detailed onboarding progress for a single host. Stages: submitting, queued, running, succeeded, failed, timeout.
Response:
{
"ip": "198.51.100.7",
"stage": "succeeded",
"message": "Device onboarded (core-switch-02)",
"job_result_id": "uuid",
"device_id": "uuid"
}These endpoints expose the MAC-keyed endpoint store backed by the
mnm_controller PostgreSQL database. They return empty results if the database
is unreachable; the controller will fall back to JSON for /api/config only.
Return the current identity record for one MAC.
Return all endpoint_events rows for a MAC, newest first.
Response: {"mac": "...", "events": [{"event_type": "moved_port", "old_value": "ge-0/0/12", "new_value": "ge-0/0/24", "timestamp": "..."}, ...]}
Return a chronological narrative for a MAC. Each entry has a human-readable
text describing the event, plus the underlying event_type and timestamp.
Response also includes the current endpoint record.
Recent network activity feed. Query params:
type(optional) —appeared,moved_port,moved_switch,ip_changed,hostname_changedsince(default24h) — duration string:1h,24h,7d,30dlimit(default200)
Return IPs currently claimed by more than one MAC. Each entry includes the list of conflicting endpoints with their switch/port context.
# Last day of port moves
curl -b cookies.txt 'http://localhost:9090/api/endpoints/events?type=moved_port&since=24h'
# Full timeline for one endpoint
curl -b cookies.txt http://localhost:9090/api/endpoints/AA:BB:CC:DD:EE:FF/timeline