NetStacksNetStacks

Stacks & Deployments API

Enterprise

Create config stacks, preview what they render per device, save instances, run deployments, follow their logs, and roll back through the NetStacks Controller API.

Overview

A stack is an ordered list of services. Each service points at one template and can carry default variable values. A deployment renders the stack for chosen devices and pushes the result. An instance is a saved, ready-to-run deployment (devices and values filled in) that you can deploy later or on a schedule.

All endpoints are under /api/config and need devices.access. They are not in the Swagger UI. For the UI workflow, see Creating stacks.

Endpoints

Stacks

MethodPathPurposePermission
GET/api/config/stacksList stacks (array). Query: limit, offsetdevices.access
POST/api/config/stacksCreate a stackdevices.access
GET/api/config/stacks/:idGet a stackdevices.access
PUT/api/config/stacks/:idUpdate a stack (only the fields you send)devices.access
DELETE/api/config/stacks/:idDelete a stack (204)devices.access
POST/api/config/stacks/:id/renderRender every service for its devices without deployingdevices.access
POST/api/config/stacks/:id/resolve-variablesFetch variable values that are mapped to API resourcesdevices.access

Deployments

MethodPathPurposePermission
POST/api/config/deploymentsCreate and start a deploymentdevices.access
GET/api/config/deploymentsList deployments (array). Query: stack_id, limit, offsetdevices.access
GET/api/config/deployments/:idA deployment with its per-device resultsdevices.access
GET/api/config/deployments/:id/logsDeployment log lines. Query: device_id, limit (default 100, max 1000), offsetdevices.access
POST/api/config/deployments/:id/rollbackRestore the pre-deployment backupsdevices.access

Instances

MethodPathPurposePermission
GET/api/config/instancesList saved instancesdevices.access
POST/api/config/instancesCreate an instancedevices.access
GET / PUT / DELETE/api/config/instances/:idGet, update, or delete an instancedevices.access
POST/api/config/instances/:id/deployStart a deployment from the instancedevices.access

Create a stack

POST /api/config/stacksjson
{
  "name": "branch-baseline",
  "description": "Hostname, SNMP, NTP for new branch routers",
  "atomic": true,
  "services": [
    { "template_id": "a1f0...", "order": 1, "variables": {} },
    { "template_id": "7c90...", "order": 2, "variables": { "community": "n0c-ro" } }
  ]
}
FieldTypeNotes
namestringRequired.
servicesarrayRequired. Each item: template_id (string UUID), order (integer), optional variables (default values) and api_variables.
atomicbooleanDefault true.
sharedbooleanDefault false.
descriptionstringOptional.
variable_configobjectOptional per-variable settings used by the stack editor (scope shared or per_device, API-resource lookups).

The response is 201 with the stack.

The variable_values object

Rendering, deployments, and instances all use a variable_values object that says, per service, which devices it runs on and which values to use. Keys are the service's position in the services array as a string ("0", "1", …):

{
  "0": {
    "devices": ["8d1e...", "a41f..."],
    "shared_vars": { "domain": "corp.example.com" },
    "device_vars": {
      "8d1e...": { "hostname": "br-rtr-01" },
      "a41f...": { "hostname": "br-rtr-02" }
    }
  },
  "1": {
    "devices": ["8d1e...", "a41f..."],
    "shared_vars": { "location": "Branch 12" },
    "device_vars": {}
  }
}

For each device, values merge in this order, later winning: the service's default variables, then shared_vars, then that device's device_vars. A service with no devices is skipped.

Preview the rendered config

POST /api/config/stacks/:id/render with {"variable_values": {…}} renders every service for its devices and returns the results. Nothing is pushed.

{
  "jobs": [
    {
      "device_id": "8d1e...",
      "device_name": "br-rtr-01",
      "template_id": "a1f0...",
      "template_name": "hostname",
      "service_order": 1,
      "rendered_config": "{ \"hostname\": \"br-rtr-01\" }",
      "target_path": "/openconfig-system:system/config",
      "operation": "merge",
      "config_format": "json"
    }
  ]
}

A missing template, unknown device, or render error returns 400 with {"error":"Stack resolution failed: …"}.

Run a deployment

POST /api/config/deployments creates the deployment and starts it in the background. The call returns right away with 201 and the deployment in pending status.

curl -s --cacert netstacks-ca.pem -X POST https://controller.example.com:3000/api/config/deployments \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d @deploy.json
deploy.jsonjson
{
  "stack_id": "5b3e...",
  "name": "Branch 12 baseline",
  "target_devices": [ { "device_id": "8d1e..." }, { "device_id": "a41f..." } ],
  "variable_values": {
    "0": { "devices": ["8d1e...", "a41f..."], "shared_vars": {}, "device_vars": {} }
  }
}
FieldTypeNotes
stack_idstring (UUID)Required.
namestringRequired. Shown in deployment history.
target_devicesarrayRequired. [{"device_id": "…"}].
variable_valuesobjectPer-service devices and values (see above).

Before changing a device, the deployment takes a backup of its config. That backup is what rollback restores.

Credentials

Deployments log in with each device's connection profile. The profile needs an automation transport (gNMI or NETCONF) that matches the template's platform.

Follow a deployment

Poll GET /api/config/deployments/:id until status is completed or failed (it is in_progress while running). The response is the deployment plus a devices array with one entry per device and service:

{
  "id": "d77a...",
  "stack_id": "5b3e...",
  "name": "Branch 12 baseline",
  "status": "completed",
  "total_devices": 2,
  "succeeded_count": 2,
  "failed_count": 0,
  "started_at": "2026-10-12T14:00:02Z",
  "completed_at": "2026-10-12T14:00:19Z",
  "devices": [
    {
      "device_id": "8d1e...",
      "service_name": "hostname",
      "status": "completed",
      "rendered_config": "...",
      "backup_config_id": "f0c1...",
      "error_message": null
    }
  ]
}

For step-by-step detail, read GET /api/config/deployments/:id/logs. Each line has level, message, device_id, and created_at. The fields shown above are trimmed. The full deployment also includes target_devices, variable_values, and audit fields.

Roll back

POST /api/config/deployments/:id/rollback pushes each device's pre-deployment backup back to it. It only works for deployments in completed or failed status that have at least one device backup. Otherwise it returns 400. While it runs, the deployment status is rolling_back, then rolled_back.

Instances

An instance stores everything a deployment needs so it can be run again. Create one with POST /api/config/instances:

{
  "stack_id": "5b3e...",
  "name": "Branch 12 baseline",
  "target_devices": [ { "device_id": "8d1e..." } ],
  "variable_values": { "0": { "devices": ["8d1e..."], "shared_vars": {}, "device_vars": {} } }
}

POST /api/config/instances/:id/deploy (no body) starts a deployment from the instance and returns it with 201, just like POST /api/config/deployments. Instances can also be deployed by a scheduled task of type deployment.