NetStacksNetStacks

Config Backups API

Enterprise

Pull device configurations, read stored versions, compare versions, and run backup snapshots across many devices with the NetStacks Controller API.

Overview

Every config backup the Controller takes is stored as a numbered version per device. A snapshot is a backup run over a set of devices; it groups the versions it collected and tracks how many devices succeeded or failed. These are the backups shown on a device's Config Backups tab and under Config Automation → Snapshots.

All endpoints need devices.access. They are not in the Swagger UI. For the UI side, see Config snapshots.

Endpoints

Per-device backups

MethodPathPurposePermission
POST/api/config/devices/:device_id/pullBack up one device now. Query: method = cli, structured, or both (default)devices.access
POST/api/config/devices/bulk-pullBack up several devices in the background. Body: {"device_ids":[…],"method":"both"}devices.access
GET/api/config/devices/:device_id/configsList stored versions (newest first, no config text). Query: limit, offsetdevices.access
GET/api/config/devices/:device_id/configs/latestThe newest stored version, with config textdevices.access
GET/api/config/devices/:device_id/configs/:versionOne stored version, with config textdevices.access
PUT/api/config/devices/:device_id/configs/:version/notesSet operator notes on a version. Body: {"notes":"…"}devices.access
GET/api/config/devices/:device_id/diff-versionsUnified diff of two stored versions. Query: old_version, new_versiondevices.access

Snapshots

MethodPathPurposePermission
GET/api/devices/snapshotsList snapshots: {"snapshots":[…],"total":n}devices.access
POST/api/devices/snapshotsCreate a snapshot definitiondevices.access
GET/api/devices/snapshots/:idGet a snapshot: {"snapshot":{…}}devices.access
DELETE/api/devices/snapshots/:idDelete a snapshot (204)devices.access
POST/api/devices/snapshots/:id/collectCollect configs from the matching devicesdevices.access
POST/api/devices/snapshots/:id/recollect-failedCollect again from only the devices that faileddevices.access
GET/api/devices/snapshots/:id/backupsPer-device results of the snapshotdevices.access
GET/api/devices/snapshots/backups/:config_id/logThe session transcript of one device backup: {"log":"…"}devices.access

Back up one device

POST /api/config/devices/:device_id/pull logs in with the device's connection profile and stores the running config. cli uses SSH; structured uses the profile's gNMI or NETCONF transport. With both, each method is tried and stored on its own.

curl -s --cacert netstacks-ca.pem -X POST \
  "https://controller.example.com:3000/api/config/devices/8d1e.../pull?method=cli" \
  -H "Authorization: Bearer $TOKEN"

On success the response is 201:

{ "message": "Config pull complete", "structured": false, "cli": true }

If every requested method fails, the response is 502. The failed attempts are still stored as versions with status: "failed" and an error_message, so you can see why on the device's Config Backups tab.

POST /api/config/devices/bulk-pull returns 202 right away with {"message", "snapshot_id", "devices_queued"}. The work runs in the background as a snapshot; follow it with GET /api/devices/snapshots/:snapshot_id.

Read stored versions

GET /api/config/devices/:device_id/configs returns {"configs":[…],"total":n}. Each item describes one version without the config text:

{
  "id": "f0c1...",
  "device_id": "8d1e...",
  "version": 14,
  "config_format": "cli",
  "config_hash": "9b2f...",
  "source": "pull",
  "pulled_via": "ssh",
  "status": "success",
  "error_message": null,
  "snapshot_id": null,
  "notes": "Before WAN cutover",
  "notes_by": "jdoe",
  "created_at": "2026-10-12T02:00:07Z"
}

Fetch the text with /configs/latest or /configs/:version. Those responses add config_text.

Compare versions

curl -s --cacert netstacks-ca.pem \
  "https://controller.example.com:3000/api/config/devices/8d1e.../diff-versions?old_version=13&new_version=14" \
  -H "Authorization: Bearer $TOKEN"
{
  "old_version": 13,
  "new_version": 14,
  "old_format": "cli",
  "new_format": "cli",
  "identical": false,
  "diff": " hostname core-sw-01\n-ntp server 10.0.0.5\n+ntp server 10.0.0.6\n ...",
  "additions": 1,
  "deletions": 1
}

diff lists the config line by line. Removed lines start with -, added lines with +, and unchanged lines with a space. A version that doesn't exist returns 404.

Snapshots (many devices)

A snapshot is created first, then collected:

# 1. Create the snapshot (optionally limited to a site and/or device type)
SNAP=$(curl -s --cacert netstacks-ca.pem -X POST https://controller.example.com:3000/api/devices/snapshots \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"Pre-change HQ","device_filter":{"site_id":"c07b...","device_type":"cisco_ios"}}' \
  | jq -r .snapshot.id)

# 2. Collect configs from the matching devices (runs in the background)
curl -s --cacert netstacks-ca.pem -X POST https://controller.example.com:3000/api/devices/snapshots/$SNAP/collect \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{}'

# 3. Check progress and per-device results
curl -s --cacert netstacks-ca.pem https://controller.example.com:3000/api/devices/snapshots/$SNAP \
  -H "Authorization: Bearer $TOKEN" | jq '.snapshot | {status, total_devices, successful_devices, failed_devices}'
curl -s --cacert netstacks-ca.pem https://controller.example.com:3000/api/devices/snapshots/$SNAP/backups \
  -H "Authorization: Bearer $TOKEN"
  • device_filter accepts site_id and device_type. Leave it out (or send {}) for all devices.
  • collect accepts an optional timeout_seconds and returns 202 with devices_queued. If no devices match, it returns 400 “No devices match the filter”.
  • Each entry in /backups has device_name, version, size_bytes, line_count, backup_method, status, and error_message.
Plain-text errors

The snapshot endpoints return error messages as plain text (for example Snapshot not found), not as a JSON object. See Errors.