Devices API
EnterpriseList, create, update, import, and delete devices in the NetStacks Controller inventory, plus sites and NetBox sources.
Overview
The devices endpoints manage the Controller's shared inventory: the same list shown under Inventory → Managed Devices in the Admin Console and in the Terminal's device list in enterprise mode.
Every device belongs to one organization and uses one connection profile for its credentials. All endpoints on this page need the devices.access permission.
Endpoints
| Method | Path | Purpose | Permission |
|---|---|---|---|
GET | /api/devices | List devices (filters and paging below) | devices.access |
POST | /api/devices | Create a device | devices.access |
GET | /api/devices/:id | Get one device | devices.access |
PUT | /api/devices/:id | Update a device (only the fields you send) | devices.access |
DELETE | /api/devices/:id | Delete a device (204) | devices.access |
POST | /api/devices/import/csv | Import from CSV text. Optional ?profile_id= | devices.access |
POST | /api/devices/import/json | Import from a JSON array. Optional ?profile_id= | devices.access |
PATCH | /api/devices/bulk | Set the same fields on many devices | devices.access |
POST | /api/devices/:id/test-credential | Test that the device's credentials can log in | devices.access |
POST | /api/devices/bulk/test-credentials | Test credentials on several devices. Body: {"device_ids":[…]} | devices.access |
GET | /api/devices/with-backup-info | Devices with their latest config backup details | devices.access |
GET | /api/devices/:id/interfaces | Interfaces collected by discovery | devices.access |
GET | /api/devices/:id/neighbors | CDP/LLDP neighbors collected by discovery | devices.access |
GET | /api/devices/:id/arp-table | ARP entries collected by discovery | devices.access |
GET | /api/devices/:id/mac-table | MAC table entries collected by discovery | devices.access |
GET | /api/devices/:id/vlans | VLANs collected by discovery | devices.access |
GET | /api/devices/:id/status | Latest poll status | devices.access |
POST | /api/devices/:id/poll | Queue a discovery poll of this device now | devices.access |
GET | /api/devices/:id/poll-history | Recent poll results | devices.access |
GET | /api/sites | List sites | devices.access |
POST | /api/sites | Create a site | devices.access |
GET / PUT / DELETE | /api/sites/:id | Get, update, or delete a site | devices.access |
List and search devices
GET /api/devices returns a page of device summaries. Query parameters (all optional):
| Field | Type | Notes |
|---|---|---|
q | string | Free-text search across name, host, manufacturer, model, platform, and device type |
vendor | string | Manufacturer, case-insensitive exact match |
platform | string | Platform, exact match |
device_type | string | Device type, for example cisco_ios |
site_id | UUID | Devices assigned to this site |
site | string | Free-text site name |
source | string | manual, csv, json, netbox, … |
limit / offset | integer | Paging. Default 50, maximum 100 |
curl -s --cacert netstacks-ca.pem \
"https://controller.example.com:3000/api/devices?q=core&limit=25" \
-H "Authorization: Bearer $TOKEN"{
"devices": [
{
"id": "8d1e...",
"org_id": "0000...0001",
"name": "core-sw-01",
"host": "10.0.0.11",
"device_type": "cisco_ios",
"manufacturer": "Cisco",
"model": "C9300-48P",
"site": "HQ",
"source": "manual",
"profile_id": "51a2...",
"created_at": "2026-09-14T08:12:00Z",
"updated_at": "2026-10-01T16:40:00Z"
}
],
"total": 1,
"limit": 25,
"offset": 0
}GET /api/devices/:id returns the full record, which adds protocol, description, platform, serial_number, asset_tag, tags, metadata, site_id, poll_enabled, poll_interval_minutes, NetBox fields, and audit fields.
Create a device
POST /api/devices returns 201 with the new device. A connection profile is required.
curl -s --cacert netstacks-ca.pem -X POST https://controller.example.com:3000/api/devices \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "edge-rtr-02",
"host": "10.0.1.2",
"device_type": "cisco_xe",
"manufacturer": "Cisco",
"profile_id": "51a2...",
"site_id": "c07b...",
"tags": ["edge", "wan"]
}'| Field | Type | Notes |
|---|---|---|
name | string | Required. Must be unique in the organization. |
host | string | Required. IP address or hostname. |
device_type | string | Required. The Admin Console uses cisco_ios, cisco_nxos, cisco_xe, cisco_xr, juniper_junos, arista_eos, paloalto_panos, fortinet, generic, custom, snmp. |
profile_id | UUID | Required. The connection profile to use. |
protocol | string | Default ssh. |
manufacturer, model, platform, description | string | Optional. |
serial_number, asset_tag | string | Optional. |
site_id | UUID | Optional. A site from /api/sites. |
tags | string[] | Optional. |
metadata | object | Optional free-form JSON. |
poll_enabled | boolean | Default false. Turns on background polling. |
poll_interval_minutes | integer | Optional polling interval. |
Creating a device with a name that already exists returns 409with {"error":"Device with this name already exists"}.
Update and delete
PUT /api/devices/:id accepts any of the create fields (except source) and changes only the ones you send:
curl -s --cacert netstacks-ca.pem -X PUT https://controller.example.com:3000/api/devices/8d1e... \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"description": "Core switch, rack A3", "poll_enabled": true}'DELETE /api/devices/:id returns 204, or 404 if the device doesn't exist in your organization.
Bulk import (CSV / JSON)
Both import endpoints create one device per row. Rows that fail don't stop the import. Pass ?profile_id=<uuid> to choose the connection profile for the imported devices. Without it, the default profile from Settings → Manage is used. If neither is set, the call returns 400.
CSV: send the file as the request body. The header row must use these exact column names. name, host, and device_type are required; the rest are optional.
name,host,device_type,manufacturer,model,platform,site,description
core-sw-01,10.0.0.11,cisco_ios,Cisco,C9300-48P,,HQ,Core switch
fw-01,10.0.0.1,paloalto_panos,Palo Alto,PA-3220,,HQ,Perimeter firewallcurl -s --cacert netstacks-ca.pem -X POST \
"https://controller.example.com:3000/api/devices/import/csv?profile_id=51a2..." \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: text/csv" \
--data-binary @devices.csvJSON: send an array of objects with the same field names to /api/devices/import/json.
Both return a summary. Row numbers in CSV errors count the header as row 1:
{
"imported": 1,
"failed": 1,
"errors": [
{ "row": 3, "name": "fw-01", "error": "Device with this name already exists" }
]
}Rows whose name already exists fail. Use PUT /api/devices/:id or the bulk edit endpoint to change existing devices. Imported devices use the ssh protocol and get the free-text site value, not a site_id.
Bulk edit
PATCH /api/devices/bulk sets the same values on a list of devices. Send the device IDs and only the fields you want to change. The Admin Console uses it for vendor, platform, model, device type, site, profile, polling, and tags.
{
"ids": ["8d1e...", "a41f..."],
"fields": { "profile_id": "51a2..." }
}The response is {"updated": 2}. An empty ids list or an empty fields object returns 400. To move devices to another profile you can also use POST /api/profiles/assign (see Connection profiles).
Sites
Sites group devices by location. POST /api/sites takes:
| Field | Type | Notes |
|---|---|---|
name | string | Required. |
description | string | Optional. |
location | string | Optional, for example a street address. |
parent_site_id | UUID | Optional parent site, for nesting. |
Set a device's site_id to place it in a site. Sites need devices.access, like devices.
NetBox sources
Saved NetBox connections live under /api/devices/sources/netbox. These endpoints back the NetBox import in the Admin Console:
| Method | Path | Purpose | Permission |
|---|---|---|---|
GET | /api/devices/sources/netbox | List saved NetBox sources (tokens are never returned) | devices.access |
POST | /api/devices/sources/netbox | Create a source: name, url, token, device_filters, verify_ssl, … | devices.access |
GET / PUT / DELETE | /api/devices/sources/netbox/:source_id | Get, update, or delete a source | devices.access |
POST | /api/devices/sources/netbox/:source_id/test | Test the connection and count matching devices | devices.access |
POST | /api/devices/sources/netbox/:source_id/sync | Import or update devices from this source now | devices.access |
GET | /api/devices/sync/history | Past NetBox sync results | devices.access |
A sync returns counts: added, updated, unchanged, failed, removed, plus errors and duration_ms. For the UI side, see NetBox import.