Netmon Docs · API Reference

Devicesv7.0.20

Every endpoint anchored to the device record, from creating and editing devices through tags, profiles, credentials, pending-device import, per-user dashboards, network-discovery helpers, and Hyper-V inventory.

Devices are the core inventory of the appliance: every monitored host, switch, server, or virtual machine the system tracks. Each device carries an IP address, a display label, a profile (which determines the widgets and trackers shown on its dashboard), and optional SNMP, agent, NetFlow, and port-monitoring settings. The device record is the anchor for ping latency, interface counters, SNMP/agent walks, disk and port history, alerts, and tags.

These endpoints belong to the devices functional area; an MCP or OAuth token needs the mcp:devices scope, and the calling user needs the Laravel permission shown on each endpoint. The two device permissions are devices (read and dashboard interaction) and write_devices (create, edit, delete, credentials, and pending-device import); a few list endpoints also accept overwatch. The permission is enforced regardless of how the bearer token was obtained.

Tag-scoping applies across this chapter. Most list and read endpoints filter their results to the tags the calling user is restricted to: a tag-restricted user sees only devices (and ARP rows, bandwidth, pending rows, Hyper-V cross-references) that fall inside their tags, while a user with no tag restriction sees everything. The sa (super-admin) role bypasses tag-scoping entirely. Where an endpoint takes a device id, requesting a device outside your tag scope returns 404 (it is indistinguishable from a non-existent device, by design — this prevents enumeration of devices you cannot see).

Reserved local device. Device id 1 is the appliance’s own loopback device (127.0.0.1). It always exists and cannot be deleted.

The device inventory

List devices

GET/api/devicesdevices

Permission devices (or overwatch)

Returns every device visible to the caller. Optional relations are loaded only when you ask for them, which keeps the default payload light. SNMP credentials are never included in the list payload — read a single device to retrieve its (masked) SNMP config.

Query parameters

NameTypeNotes
tagstringFilter to devices carrying this tag slug.
statusstringup (latency ≥ 0) or down (latency -1).
searchstringCase-insensitive match on label or ip_address.
alerts, ping, oids, walks, interfaces, ports, disksbooleanSet any to true to eager-load that relation onto each device.

Response 200

{
  "status": 200,
  "devices": [
    {
      "id": 1,
      "label": "Netmon Appliance",
      "ip_address": "127.0.0.1",
      "profile": "linux",
      "enable_snmp": false,
      "enable_agent": false,
      "tags": [ { "slug": "core", "name": "Core", "type": "device" } ]
    }
  ]
}

Example

curl -sS "https://APPLIANCE/api/devices?status=down&ping=true" \
  -H "Authorization: Bearer $TOKEN"

Get one device

GET/api/device/{device}devices

Returns a single device with its tags, alerts, masked SNMP config, syslog severity, recent NetFlow summary, and time-series logs for ping, OIDs, interfaces, ports, and disks. The time window defaults to the last 8 hours; pass hours, or an explicit start_time/end_time pair, to change it.

Path parameters

NameTypeNotes
deviceintegerDevice id. Out-of-scope or unknown ids return 404.

Query parameters

NameTypeNotes
hoursintegerLook-back window in hours (default 8). Ignored when start_time/end_time are given.
start_timedatetimeWindow start (any parseable date/time). Requires end_time.
end_timedatetimeWindow end.
Encrypted field

The returned snmpconfig masks the SNMP community and v3 auth/priv passwords as {"__encrypted__": true}. The plaintext secret never leaves the appliance. To preserve a secret on a later save, replay the same sentinel; to change it, send the new plaintext (see Add or edit a device).

Response 200

{
  "status": 200,
  "device": {
    "id": 42,
    "label": "core-switch",
    "ip_address": "10.0.0.1",
    "profile": "cisco",
    "tags": [ "…" ],
    "snmpconfig": { "snmp_version": 2, "snmp_community": { "__encrypted__": true } },
    "syslogconfig": { "severity": 7 },
    "netflow": { "bytes": 10485760, "count": 1432, "top_partners": [ "…" ] }
  }
}

Example

curl -sS "https://APPLIANCE/api/device/42?hours=24" \
  -H "Authorization: Bearer $TOKEN"

Get device storage stats

GET/api/device/{device}/statsdevices

Returns the row counts and on-disk size of every per-device log category (syslog, event log, trackers, interfaces, disks, walks, ports, ping), plus a Total row. Useful for understanding how much history a device is accumulating.

Path parameters

NameTypeNotes
deviceintegerDevice id.

Response 200

[
  { "log_name": "Syslog", "total_rows": 12044, "size": 5242880, "formatted": "5120 kB" },
  { "log_name": "Interfaces", "total_rows": 8800, "size": 2097152, "formatted": "2048 kB" },
  { "log_name": "Total", "total_rows": 20844, "size": 7340032, "formatted": "7168 kB" }
]

Errors

StatusBodyWhen
400{"message":"Invalid device ID"}Non-numeric id.
404{"message":"Device not found"}Out-of-scope or unknown device.
500{"message":"An error occurred while fetching stats"}Query failure.

Adding and editing devices

Add or edit a device

POST/api/device/setwrite_devices

Creates a new device, or updates an existing one when id is supplied. The same endpoint configures SNMP and replaces the device’s tag set. On create, any matching pending-device row for the same IP is removed.

Request body

FieldTypeRequiredNotes
idintegernoOmit to create; include to update.
ip_addressstring (IP)yesMust be a valid IP. Unique across devices.
labelstringyesMax 255.
profilestringyesDashboard profile slug (see List device profiles).
enable_snmpbooleannoDefaults to false when absent.
enable_agentbooleannoWindows-agent monitoring.
enable_netflowbooleannoNetFlow association.
enable_port_monitorbooleannoTCP/UDP port monitoring. Not clobbered on partial update if omitted.
agent_uuidstringnoInternal agent identity; only written when present, never cleared by omission.
snmpconfigobjectnoRead when enable_snmp is true (see below).
tagsarraynoEach item {slug, name, type:"device"}. Replaces the device’s existing tags.

snmpconfig fields: snmp_version (1, 2, or 3; default 2), snmp_port (default 161); for v1/v2 snmp_community; for v3 snmp_v3_security, authuser, authpass, authprot, privpass, privprot.

Encrypted field

For snmp_community, authpass, and privpass, send the {"__encrypted__": true} sentinel (or an empty value) to keep the stored secret unchanged; send fresh plaintext to replace it. This mirrors the masking returned by Get one device.

Response 200

{ "status": 200, "message": "Device created successfully", "device": { "id": 43, "tags": [ "…" ] } }

Errors

StatusBodyWhen
422{"status":422,"errors":{...}}Validation failed.
409{"status":409,"message":"A device with IP address … already exists…"}Duplicate IP.
500{"status":500,"message":"An error occurred while saving the device: …"}Save error.

Example

curl -sS -X POST https://APPLIANCE/api/device/set \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"ip_address":"10.0.0.5","label":"edge-fw","profile":"fortigate",
       "enable_snmp":true,
       "snmpconfig":{"snmp_version":2,"snmp_port":161,"snmp_community":"public"},
       "tags":[{"slug":"edge","name":"Edge","type":"device"}]}'

Delete a device (RESTful)

DELETE/api/device/{device}write_devices

Permission devices and write_devices (both required)

Detaches the device’s tags and deletes the device row, cascading to its monitoring history.

Destructive

This permanently removes the device and all of its associated monitoring data (ping, interface, SNMP, disk, port, and log history). It cannot be undone.

Path parameters

NameTypeNotes
deviceintegerDevice id. Out-of-scope/unknown returns a 500 with a not-found message.

Response 200

{ "status": 200, "message": "Device deleted successfully" }

Delete a device (legacy form)

POST/api/deleteDevicewrite_devices

Older delete entry point that takes the device id in the body. Prefer the RESTful DELETE /api/device/{device} above for new automation.

Destructive

Permanently deletes the device and its monitoring history.

Request body

FieldTypeRequiredNotes
deviceintegeryesDevice id (must be > 0).

Response

{ "status": 201, "hasError": false, "message": true }

On a missing id the response carries {"status": false, "hasError": true, "message": "Device ID requried"}.

Re-crawl a device

POST/api/device/{device}/recrawlwrite_devices

Permission devices and write_devices (both required)

Queues a fresh discovery crawl of the device. The appliance re-examines the device on its next polling tick — useful after changing credentials or expecting new interfaces.

Path parameters

NameTypeNotes
deviceintegerDevice id.

Response 200

{ "status": 200, "message": "Re-crawl queued" }

Test SNMP reachability

POST/api/testSnmpwrite_devices

Runs a live SNMP probe against a target IP using the supplied SNMP config, without saving anything. Use it to validate credentials before creating or editing a device.

Request body

FieldTypeRequiredNotes
ipstringyesTarget IP to probe.
snmpconfigobjectyesSame shape as on Add or edit a device.
device_idintegernoWhen given, masked/blank secrets resolve from this device’s stored credential.
Encrypted field

A masked secret ({"__encrypted__": true}) or blank value is resolved from the device named by device_id; literal plaintext is used as-is. This lets the appliance validate a credential the caller never sees in plaintext.

Response 200

{ "status": 200, "message": "SNMP responded: …" }

A failed probe returns {"status": 301, "message": "…"}; an internal error returns {"status": false, "message": "…"}.

Device tags

Tags group devices and drive tag-scoping. The device-level endpoints add or remove tags on a single device; the catalog endpoint lists all tags in the system.

List all tags

GET/api/tagsdevices

Permission devices (or overwatch, or write_devices)

Returns every tag defined on the appliance (device tags and any other types).

Response 200

{ "status": 200, "tags": [ { "id": 3, "slug": "edge", "name": "Edge", "type": "device" } ] }

List a device’s tags

GET/api/device/{device}/tagsdevices

Returns the device-type tags attached to one device.

Path parameters

NameTypeNotes
deviceintegerDevice id.

Response 200

{ "status": 200, "tags": [ { "name": "Edge", "slug": "edge", "type": "device" } ] }

Add tags to a device

POST/api/device/{device}/tagswrite_devices

Permission devices and write_devices (both required)

Attaches one or more device tags, creating any tag that does not yet exist (matched by slug + type).

Path parameters

NameTypeNotes
deviceintegerDevice id.

Request body

FieldTypeRequiredNotes
tagsarrayyesOne or more tag objects.
tags.*.slugstringyesTag slug.
tags.*.namestringyesMax 255.
tags.*.typestringyesMust be device.

Response 201

{ "status": 201, "message": "Tags added successfully" }

A validation failure returns 400 with {"status": false, "errors": {...}}.

Remove tags from a device

DELETE/api/device/{device}/tagswrite_devices

Permission devices and write_devices (both required)

Detaches the named tags from the device.

Path parameters

NameTypeNotes
deviceintegerDevice id.

Request body

FieldTypeRequiredNotes
tagsarrayyesOne or more {slug} objects.
tags.*.slugstringyesMust reference an existing tag.

Response 200

{ "status": 200, "message": "Tags removed successfully" }

Device profiles and credentials

List device profiles

GET/api/device/profilesdevices

Permission devices (or overwatch, or write_devices)

Returns the catalog of device profiles. A profile defines the default dashboard layout and trackers used when a device of that type is added.

Response 200

{ "status": 200, "profiles": [ { "id": 1, "profile": "linux", "layout": [ "…" ] } ] }

List autodiscovery credentials

GET/api/getCredentialswrite_devices

Returns the saved SNMP credential sets used by network autodiscovery.

Response 200

{ "status": 201, "hasError": false, "data": [ { "id": 1, "label": "Default v2", "authuser": null } ] }

Add, edit, or delete a credential

POST/api/addEditCredentialwrite_devices

Creates or updates a credential set (action: "addedit"), or deletes one (action: "delete"). On add/edit, omit id to create; include it to update.

Request body

FieldTypeRequiredNotes
actionstringyesaddedit or delete.
idintegerconditionalRequired for delete; optional for addedit (omit to create).
labelstringfor addeditDisplay label.
authuserstringfor addeditSNMP v3 username.
snmp_authprotstringfor addeditv3 auth protocol.
snmp_privprotstringfor addeditv3 privacy protocol.
snmp_communitystringnoEncrypted at rest when present.
authpassstringnoEncrypted at rest when present.
snmp_privpassstringnoEncrypted at rest when present.
Encrypted field

snmp_community, authpass, and snmp_privpass are encrypted on save and not returned in plaintext. Omit a secret to leave it unchanged.

Response 201 (addedit)

{ "status": 201, "hasError": false, "credential": { "id": 4, "label": "Edge v3" } }

Response 201 (delete)

{ "status": 201, "hasError": false, "message": "Delete Success" }

Unknown or missing action returns {"status": false, "hasError": true, "message": "…"}.

Agent installer download

Download the Windows agent installer

GET/api/agent/download

Permission any authenticated user or a valid signed URL

Streams the latest Windows agent installer for the requested architecture. Covered more fully in the Agents chapter.

Signed-URL route

This route accepts either a Passport bearer token or a valid, unexpired URL signature (query parameters) in place of a token. The signed form is minted inside an authenticated agent check-in response and is honored without a bearer token. The endpoint is not behind a permission: gate — access is the bearer token or the signature itself.

Query parameters

NameTypeNotes
archstringamd64 (default) or arm64.

Response 200 — binary file (Content-Type: application/octet-stream); the filename is the staged installer name, e.g. netmon-agent-installer-<version>-<arch>.exe.

Errors

StatusBodyWhen
400{"status":false,"message":"Unsupported arch (expected amd64 or arm64)."}Bad arch.
404{"status":false,"message":"Agent installer not present on this server."}No installer staged.

Example

curl -sS "https://APPLIANCE/api/agent/download?arch=amd64" \
  -H "Authorization: Bearer $TOKEN" -o netmon-agent.exe

Pending devices (import)

Devices discovered by network scans or self-reported by Windows agents land in a pending queue for operator review before they become monitored devices. All pending-device endpoints require write_devices and are tag-scoped: tag-restricted operators see and act on only pending rows whose tags overlap their slice.

List pending devices

POST/api/getDevicesPendingwrite_devices

Returns pending (un-imported) devices plus the discovery-scan status for each local network. Takes no body.

Response

{
  "status": 201,
  "hasError": false,
  "devices": [
    {
      "id": 7, "label": "host-7", "ip_address": "10.0.0.7",
      "profile": "windows", "enable_agent": true, "agent_uuid": "…",
      "last_checkin_at": "2026-06-15T12:00:00Z", "agent_version": "1.4.0",
      "os_version": "Windows 11", "tags": [],
      "snmpconfig": { "snmp_version": 2, "snmp_community": "…" }
    }
  ],
  "discovery_status": [ { "id": 1, "net_id": 1, "start_time": "…", "end_time": "…" } ]
}

Import (adopt) a pending device

POST/api/importPendingwrite_devices

Promotes a pending device to a monitored device, copying its IP, label, profile, agent/SNMP settings, and applying the supplied tags. The pending row is removed on success. Rejected if a device with the same IP already exists.

Request body

FieldTypeRequiredNotes
idintegeryesPending-device id.
tagsarrayno{slug, name, type:"device"} items applied to the adopted device.

Response 201

{ "status": 201, "hasError": false, "message": "Import Successful" }

A duplicate IP returns {"status": false, "hasError": true, "message": "A device with the IP address … already exists."}.

Hide a pending device

POST/api/hidePendingDevicewrite_devices

Hides a pending row from the default import list without deleting it.

Request body

FieldTypeRequiredNotes
idintegeryesPending-device id.

Response 201

{ "status": 201, "hasError": false, "message": "Device hidden successfully" }

Remove a pending device

POST/api/removePendingDevicewrite_devices

Permanently deletes a pending row from the import queue.

Destructive

Deletes the pending-device record. The device may reappear if discovery or an agent check-in detects it again.

Request body

FieldTypeRequiredNotes
idintegeryesPending-device id.

Response 201

{ "status": 201, "hasError": false, "message": "Device removed successfully" }

Update a pending device field

POST/api/updatePendingDeviceFieldwrite_devices

Edits a single field on a pending device before import (for example, correcting the profile or supplying SNMP credentials).

Request body

FieldTypeRequiredNotes
idintegeryesPending-device id.
fieldstringyesOne of label, profile, enable_snmp, enable_agent, snmp_community, snmp_port, snmp_version, snmp_v3_security, authuser, authpass, authprot, privpass, privprot.
valuemixedyesNew value. Secret fields (snmp_community, authpass, privpass) are encrypted on save.

Response 201

{ "status": 201, "hasError": false, "message": "Device updated successfully" }

Validation failures return 422 with {"status": false, "hasError": true, "message": {...}}.

Update a pending device’s tags

POST/api/updatePendingDeviceTagswrite_devices

Replaces the tag set on a pending device. Tags carried into import via importPending come from here.

Request body

FieldTypeRequiredNotes
idintegeryesPending-device id.
tagsarrayyesOne or more {slug, name, type:"device"} objects.

Response 201

{ "status": 201, "hasError": false, "message": "Tags updated successfully" }

Dashboards, layouts, and trackers

These endpoints persist per-user dashboard state — the home dashboard, per-device widget layouts, pinned widgets, and the trackers shown on a device page. Layout/pinned-widget writes are tag-scoped to the device id.

Get the user’s dashboards

GET/api/getDashboards

Permission any authenticated user

Returns the calling user’s saved home dashboards and their layouts. New users with no saved state get empty objects.

Response 200

{ "dashboards": {}, "layouts": {} }

Save the user’s dashboards

POST/api/setDashboards

Permission any authenticated user

Upserts the calling user’s home dashboards and layouts.

Request body

FieldTypeRequiredNotes
dashboardsobjectnoDashboard definition map.
layoutsobjectnoLayout map.

Response 201

{ "message": "Updated layouts" }

Add a widget to a dashboard

POST/api/addWidgetToDashdevices

Appends a single widget to a named dashboard of the calling user, creating the dashboard if it does not yet exist.

Request body

FieldTypeRequiredNotes
dashboardNamestringyesTarget dashboard name.
widgetobjectyesMust contain a positive widgetId.

Response 201

{ "status": "success" }

Invalid input returns 400 with {"error": "Invalid parameter"}.

Get a device’s trackers and layout

GET/api/getDeviceTrackersdevices

Returns the available tracker widgets for a device (ping, ports, OIDs, interfaces, disks, and Hyper-V VM trackers), merged with the profile’s default layout, plus the calling user’s saved layout and pinned widgets for that device.

Query parameters

NameTypeNotes
deviceIdintegerRequired. Must reference an existing device.

Response 200

{
  "hasError": false,
  "trackers": [ { "trackerId": "12", "trackerTable": "oids", "widgetId": 4, "w": 4, "h": 3 } ],
  "layouts": null,
  "pinnedWidgets": []
}

When the device has no trackers at all the endpoint returns 204 with {"message": "no trackers"}; a missing/invalid deviceId returns 422.

Save a device layout

POST/api/setDeviceLayoutsdevices

Upserts the calling user’s saved widget layout for one device.

Request body

FieldTypeRequiredNotes
deviceIdintegeryesDevice id (tag-scoped).
layoutsarray/objectyesGrid layout payload.

Response 201

{ "hasError": false, "message": "Device trackers set successfully." }

Missing parameters return 400; an out-of-scope deviceId returns 404.

Save device pinned widgets

POST/api/setDevicePinnedWidgetsdevices

Upserts the calling user’s pinned-widget set for one device.

Request body

FieldTypeRequiredNotes
deviceIdintegeryesDevice id (tag-scoped).
pinnedWidgetsarray/objectyesPinned-widget payload.

Response 201

{ "hasError": false, "message": "Pinned widgets set successfully." }

Delete a device layout

POST/api/deleteDeviceLayoutsdevices

Deletes the calling user’s saved layout for one device, reverting that device’s dashboard to the profile default.

Request body

FieldTypeRequiredNotes
deviceIdintegeryesDevice id (tag-scoped).

Response 201

{ "hasError": false, "message": "Device layouts deleted successfully." }

Returns 404 when no saved layout exists for that device and user, 400 when deviceId is missing.

Latency tracker history

POST/api/getLatencyTrackerdevices

Returns the ping latency/loss time series for a device’s ICMP probe over the requested window.

Request body

FieldTypeRequiredNotes
deviceIdintegeryesDevice id (tag-scoped).
hoursintegernoLook-back window in hours (default 4).

Response 200

{
  "status": 200, "hasError": false,
  "message": {
    "dev_label": "core-switch", "dev_ip": "10.0.0.1",
    "logs": [ { "icmping_id": 5, "latency": 1.2, "loss": 0, "timestamp": 1718450000 } ]
  }
}

When the device has no ping probe the endpoint returns {"status": 204, "hasError": false, "message": {}}.

TCP/port tracker history

POST/api/getTCPTrackerdevices

Returns the latency time series for one monitored TCP/UDP port on a device.

Request body

FieldTypeRequiredNotes
deviceIdintegeryesDevice id (tag-scoped).
idintegeryesPort (tracker) id.
hoursintegernoLook-back window in hours (default 4).

Response 200

{
  "status": 200, "hasError": false,
  "message": {
    "dev_label": "edge-fw", "port": 443,
    "logs": [ { "port_id": 9, "latency": 4.1, "timestamp": 1718450000 } ]
  }
}

Missing deviceId/id, or no matching port, returns {"status": 204, "hasError": false, "message": {}}.

Network discovery helpers

These endpoints surface ARP and NetFlow data used by the network-overview dashboard. All are tag-scoped to the calling user’s device IPs.

Recently seen hosts

POST/api/getRecentHostdevices

Returns the most recent ARP sighting per IP (unicast addresses only) within the look-back window, joined to a hostname where one is known.

Request body

FieldTypeRequiredNotes
hoursintegernoLook-back window in hours (default 1).

Response 200

{
  "status": 200, "hasError": false,
  "hosts": [ { "ip": "10.0.0.7", "mac": "aa:bb:cc:00:11:22", "hostname": "host-7", "device_id": 7 } ]
}

ARP table

POST/api/getArpTabledevices

Returns the latest ARP entry per IP over a window, with optional search across IP, MAC, and hostname.

Request body

FieldTypeRequiredNotes
hoursintegernoLook-back window in hours (default 24).
searchstringnoCase-insensitive match on IP, MAC, or hostname.

Response 200

{
  "status": 200, "hasError": false,
  "hosts": [ { "ip": "10.0.0.7", "mac": "aa:bb:cc:00:11:22", "hostname": "host-7", "device_id": 7 } ],
  "total": 1
}

ARP scan status

GET/api/getArpScanStatusdevices

Returns the timestamp of the most recent ARP entry and the total host count in scope. Takes no body.

Response 200

{ "status": 200, "hasError": false, "last_scan": "2026-06-15T12:00:00Z", "total_hosts": 42 }

Top bandwidth talkers

GET/api/getTopBandwidth/{mins}devices

Returns the top 20 source/destination conversations by bytes over the last {mins} minutes, with hostnames where known.

Path parameters

NameTypeNotes
minsintegerLook-back window in minutes.

Response 200

{
  "status": 200, "hasError": false, "mins": 15,
  "data": [
    { "src_host": "host-a", "src_ip": "10.0.0.5", "dst_host": "host-b",
      "dst_ip": "10.0.0.9", "bytes": 10485760, "bps": 93206 }
  ]
}

Set a custom hostname

POST/api/setCustomHostnamewrite_devices

Pins a custom hostname to an IP address, overriding any auto-resolved name. Tag-restricted operators may only set hostnames for IPs inside their scope.

Request body

FieldTypeRequiredNotes
hostnamestringyesMax 255.
ip_addressstring (IP)yesTarget IP.

Response 201

{ "status": 201, "hasError": false, "message": "Custom hostname set successfully", "host": { "ip": "10.0.0.7", "hostname": "edge-fw" } }

An out-of-scope IP returns 403; validation/save errors return 500.

Get navigation counts

GET/api/getNavData

Permission any authenticated user

Returns the badge counts shown in the navigation bar — total devices, active alerts, pending devices — and the calling user’s permission slugs. All counts are tag-scoped for tag-restricted users.

Response 201

{
  "status": 201, "hasError": false,
  "data": { "devices": 42, "alerts": 3, "pending": 5, "perms": ["devices","write_devices","alerts"] }
}

Hyper-V

These endpoints expose Hyper-V virtualization inventory collected from a Windows host running the agent. They are read-only and tag-scoped to the host device.

Get Hyper-V inventory

GET/api/devices/{deviceId}/hypervdevices

Returns the latest Hyper-V inventory for a host: its virtual machines, each VM’s virtual NICs, and a monitored_device cross-reference on any NIC whose MAC matches a separately-monitored device in your scope.

Path parameters

NameTypeNotes
deviceIdintegerThe Hyper-V host’s device id.

Response 200

{
  "device_id": 42, "device_label": "hyperv-01",
  "walk_id": 880, "collected_at": "2026-06-15T12:00:00Z",
  "envelope": {
    "vms": [
      { "guid": "ABC-123", "name": "vm-web",
        "nics": [ { "mac": "00:15:5d:01:02:03",
                    "monitored_device": { "device_id": 51, "label": "vm-web" } } ] }
    ]
  }
}

Errors

StatusBodyWhen
404{"error":"No Hyper-V inventory available for this device."}No inventory collected (role absent or not yet polled).
404{"error":"Device not found."}Out-of-scope or unknown device.
500{"error":"Hyper-V inventory blob is malformed."}Stored inventory could not be parsed.

Get VM CPU history

GET/api/devices/{deviceId}/hyperv/vm/{vmGuid}/cpudevices

Returns the CPU-usage sparkline series for one VM on a Hyper-V host. GUID matching is case-insensitive.

Path parameters

NameTypeNotes
deviceIdintegerThe Hyper-V host’s device id.
vmGuidstringVM GUID.

Query parameters

NameTypeNotes
hoursintegerLook-back window, clamped to 1–168 (default 4).

Response 200

{
  "vm_guid": "ABC-123", "hours": 4,
  "series": [ { "ts": 1718450000, "usage_pct": 12.5 }, { "ts": 1718451800, "usage_pct": null } ]
}

Returns 404 with {"error":"No Hyper-V walk on this device."} when the host has no Hyper-V inventory.