DNA Center

DNA Center (legacy) REST APIs, configuration templates, and Plug and Play device onboarding.

DNA Center → Catalyst Center

DNA Center has been rebranded to Catalyst Center as of version 2.3.5+. The API paths remain the same (/dna/…​). This document covers the legacy DNA Center name and any patterns specific to older versions. For the full reference, see Catalyst Center Quick Reference.

API Token Authentication

Get auth token — identical to Catalyst Center
DNAC_HOST="dnac.example.com"
TOKEN=$(curl -s -k -X POST \
  "https://${DNAC_HOST}/dna/system/api/v1/auth/token" \
  -H "Content-Type: application/json" \
  -u "admin:password" | jq -r '.Token')
The /dna/ prefix in API paths has been retained even in Catalyst Center. Cisco has not changed the API base path.

Device Inventory

List all network devices
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/network-device" \
  -H "X-Auth-Token: ${TOKEN}" | jq '.response[] | {hostname, managementIpAddress, platformId, softwareVersion}'
Get device by serial number — useful for PnP correlation
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/network-device?serialNumber=FCW2345L0AB" \
  -H "X-Auth-Token: ${TOKEN}" | jq '.response[] | {hostname, managementIpAddress}'

Plug and Play (PnP) — Zero-Touch Provisioning

List PnP devices waiting for claim
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/onboarding/pnp-device" \
  -H "X-Auth-Token: ${TOKEN}" | jq '.[] | {serialNumber, hostname, state: .deviceInfo.state, pid: .deviceInfo.pid}'
Output
{
  "serialNumber": "FCW2345L0AB",
  "hostname": "floor2-sw-01",
  "state": "Unclaimed",
  "pid": "C9300-48T"
}
Claim a PnP device — assign to site with template
curl -s -k -X POST \
  "https://${DNAC_HOST}/dna/intent/api/v1/onboarding/pnp-device/claim" \
  -H "X-Auth-Token: ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "deviceClaimList": [{
      "deviceId": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee",
      "configList": [{
        "configId": "ffffffff-ffff-ffff-ffff-ffffffffffff",
        "configParameters": [
          {"key": "hostname", "value": "floor2-sw-01"},
          {"key": "mgmt_ip", "value": "10.50.2.10"}
        ]
      }]
    }],
    "siteId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
    "type": "Default"
  }' | jq
Get PnP device history — trace provisioning steps
DEVICE_ID="eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/onboarding/pnp-device/${DEVICE_ID}/history" \
  -H "X-Auth-Token: ${TOKEN}" | jq '.response[] | {timestamp, details, errorFlag}'

PnP workflow:

1. New switch boots → DHCP option 43 points to DNAC
2. Device contacts DNAC → appears in PnP device list (state: Unclaimed)
3. Admin claims device → assigns site, template, image
4. DNAC pushes day-0 config + image upgrade
5. Device reboots → state changes to Provisioned

SWIM — Software Image Management

Get available software images
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/image/importation" \
  -H "X-Auth-Token: ${TOKEN}" | jq '.response[] | {name, version, imageType, isGoldenImage: .isTaggedGolden}'
Mark an image as golden — sets it as the standard for a device family
curl -s -k -X PUT \
  "https://${DNAC_HOST}/dna/intent/api/v1/image/importation/golden" \
  -H "X-Auth-Token: ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "imageId": "11111111-1111-1111-1111-111111111111",
    "siteId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
    "deviceRole": "ALL",
    "deviceFamilyIdentifier": "Switches and Hubs"
  }' | jq
Distribute image to a device — stage before activation
curl -s -k -X POST \
  "https://${DNAC_HOST}/dna/intent/api/v1/image/distribution" \
  -H "X-Auth-Token: ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '[{
    "deviceUuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
    "imageUuid": "11111111-1111-1111-1111-111111111111"
  }]' | jq
Activate image on device — triggers reload
curl -s -k -X POST \
  "https://${DNAC_HOST}/dna/intent/api/v1/image/activation/device" \
  -H "X-Auth-Token: ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '[{
    "deviceUuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
    "imageUuidList": ["11111111-1111-1111-1111-111111111111"],
    "activateLowerImageVersion": true
  }]' | jq
SWIM follows a 3-step process: Import → Distribute (copy to device flash) → Activate (set boot variable + reload). Always distribute during business hours, activate during maintenance window.

Site Hierarchy

Get all sites
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/site" \
  -H "X-Auth-Token: ${TOKEN}" | jq '.response[] | {name: .siteNameHierarchy, type: .additionalInfo[0].attributes.type}'
Create a building in the hierarchy
curl -s -k -X POST \
  "https://${DNAC_HOST}/dna/intent/api/v1/site" \
  -H "X-Auth-Token: ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "building",
    "site": {
      "building": {
        "name": "Building-B",
        "parentName": "Global/US/Los Angeles",
        "address": "1234 Main St, Los Angeles, CA 90012",
        "latitude": 34.0522,
        "longitude": -118.2437
      }
    }
  }' | jq

Template Programmer

List all template projects
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/template-programmer/project" \
  -H "X-Auth-Token: ${TOKEN}" | jq '.[] | {name, id, templates: [.templates[]?.name]}'
Get template content — see the Jinja/Velocity template body
TEMPLATE_ID="dddddddd-dddd-dddd-dddd-dddddddddddd"
curl -s -k \
  "https://${DNAC_HOST}/dna/intent/api/v1/template-programmer/template/${TEMPLATE_ID}" \
  -H "X-Auth-Token: ${TOKEN}" | jq '{name, templateContent, templateParams: [.templateParams[].parameterName]}'
Output
{
  "name": "Day1-Access-Switch",
  "templateContent": "hostname $hostname\ninterface vlan $mgmt_vlan\n ip address $mgmt_ip $mgmt_mask\n...",
  "templateParams": ["hostname", "mgmt_vlan", "mgmt_ip", "mgmt_mask"]
}
Templates use Velocity ($variable) or Jinja2 ({{ variable }}) syntax. Velocity is the default. Bind variables appear in templateParams and must be supplied at deployment time.