Appendix: ISE API Reference

ISE Authorization Policy API Reference

Programmatic ISE policy management using curl and jq. All commands tested during the P16g wired 802.1X deployment against ISE 3.4. No GUI β€” every operation is reproducible from the terminal.

Prerequisites

Load ISE credentials from dsec
ds d000 dev/network
Verify API reachability
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/authorizationprofile?size=1" \
    -H "Accept: application/json" | jq '.SearchResult.total'

After ds d000 dev/network, these environment variables are available:

  • ISE_API_USER β€” ERS API username

  • ISE_API_PASS β€” ERS API password

  • ISE_PAN_FQDN β€” ISE PAN hostname (fallback: ISE_PAN_IP)

  • ISE_CA_CERT β€” CA certificate path for TLS verification (also ISE_MTLS_CA)

TLS verification: --cacert "${ISE_CA_CERT/\~/$HOME}" expands the literal tilde in the stored path. curl does not expand ~ β€” zsh parameter substitution /\~/$HOME is required. Never use -k / --insecure.


ISE API Surface

ISE exposes three data interfaces. Commands in this reference use all three.

API Base Path / Protocol Use

ERS

{host}/ers/config/

CRUD for profiles, endpoints, DACLs, NADs. Full object detail. REST/JSON.

OpenAPI

{host}/api/v1/policy/network-access/

Policy sets, auth/authz rules, conditions, dictionaries. REST/JSON.

MnT

{host}/admin/API/mnt/

Real-time session data, active authentications, auth logs. REST/XML (converted to JSON by netapi). Uses ERS credentials.

pxGrid

wss://{host}:8910/pxgrid/

Real-time event streaming β€” session changes, ANC actions, TrustSec updates. WebSocket + mTLS (certificate auth, not username/password).

DataConnect

tcps://{host}:2484/cpm10

Direct Oracle database access to RADIUS logs, auth history, session data. JDBC β€” not REST.


Policy Set Discovery

ISE organizes network access into policy sets. Each set contains authentication rules and authorization rules evaluated top-down by rank.

List all policy sets (tabular)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set" \
    -H "Accept: application/json" \
    | jq -r '
        ["RANK","NAME","STATE","ID"],
        (.response[] | [.rank, .name, .state, .id]) | @tsv
    ' | column -ts $'\t'
List all policy sets (JSON detail)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set" \
    -H "Accept: application/json" \
    | jq '.response[] | {name, id, state, rank, serviceName, description}'

Authorization Profiles

Authorization profiles define what happens after authentication β€” VLAN assignment, dACL, reauthentication timer.

Get a single profile by name (full detail β€” ERS)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/authorizationprofile/name/Domus_Admin_Profile" \
    -H "Accept: application/json" \
    | jq '.AuthorizationProfile | {name, vlan, daclName, accessType, reauth}'
List all profile names and IDs (summary only β€” ERS list)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/authorizationprofile?size=100" \
    -H "Accept: application/json" \
    | jq -r '
        ["NAME","ID"],
        (.SearchResult.resources[] | [.name, .id]) | @tsv
    ' | column -ts $'\t'
Full profile table with VLAN and DACL (per-profile detail lookup)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/authorizationprofile?size=100" \
    -H "Accept: application/json" \
    | jq -r '.SearchResult.resources[].id' | while read -r ID; do
    curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/authorizationprofile/${ID}" \
        -H "Accept: application/json" \
        | jq -r '.AuthorizationProfile | [.name, (.vlan.nameID // "default"), (.daclName // "none")] | @tsv'
done | column -ts $'\t'

ISE ERS API design: The list endpoint (/ers/config/authorizationprofile) returns summary objects only β€” id, name, description, link. VLAN, DACL, and reauth fields require the detail endpoint (/ers/config/authorizationprofile/{id} or /name/{name}). No ?detail=true parameter exists. The OpenAPI endpoint (/api/v1/policy/network-access/authorization-profiles) is even sparser β€” id and name only. Confirmed in ISE 3.4 ERS OpenAPI spec.


Authorization Rules β€” Read

Authorization rules within a policy set are evaluated top-down by rank. First match wins.

Set the policy set ID (from policy set discovery above)
POLICY_SET_ID="056a2880-5821-465f-adb2-90c32de0b06f"
Inspect full structure of the first rule (discover JSON shape)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq '.response[0]'
Compact summary β€” all rules with rank, name, profile, hit count
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq -r '
        ["RANK","NAME","PROFILE","HITS","STATE"],
        (.response[] | [.rule.rank, .rule.name, (.profile[0] // "none"), .rule.hitCounts, .rule.state]) | @tsv
    ' | column -ts $'\t'
Rule evaluation order with flattened conditions
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq -r '.response[] | [
        .rule.rank,
        .rule.name,
        (.profile[0] // "none"),
        .rule.hitCounts,
        ([.rule.condition | recurse(.children[]?) | select(.attributeValue?) |
          "\(.attributeName)=\(.attributeValue)"] | join(" AND "))
    ] | @tsv' | column -ts $'\t'

Authorization Rules β€” Create

Compound AND condition (multiple match criteria)

Create rule: EAP-TLS + cert CN contains "p16g" β†’ Admin profile
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -X POST \
    -d '{
      "rule": {
        "name": "Domus_Cert_Admin_P16g",
        "rank": 0,
        "state": "enabled",
        "condition": {
          "conditionType": "ConditionAndBlock",
          "isNegate": false,
          "children": [
            {
              "conditionType": "ConditionAttributes",
              "isNegate": false,
              "dictionaryName": "Network Access",
              "attributeName": "EapAuthentication",
              "operator": "equals",
              "attributeValue": "EAP-TLS"
            },
            {
              "conditionType": "ConditionAttributes",
              "isNegate": false,
              "dictionaryName": "CERTIFICATE",
              "attributeName": "Subject - Common Name",
              "operator": "contains",
              "attributeValue": "p16g"
            }
          ]
        }
      },
      "profile": ["Domus_Admin_Profile"]
    }' | jq '.'

Single condition (simpler rules)

Create rule: permit any EAP-TLS client
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -X POST \
    -d '{
      "rule": {
        "name": "EAP_TLS_Basic_Permit",
        "rank": 10,
        "state": "enabled",
        "condition": {
          "conditionType": "ConditionAttributes",
          "isNegate": false,
          "dictionaryName": "Network Access",
          "attributeName": "EapAuthentication",
          "operator": "equals",
          "attributeValue": "EAP-TLS"
        }
      },
      "profile": ["PermitAccess"]
    }' | jq '.'

Condition types:

  • ConditionAttributes β€” single condition (one dictionary/attribute/operator/value)

  • ConditionAndBlock β€” compound AND (children[] must all match)

  • ConditionOrBlock β€” compound OR (any children[] can match)

  • ConditionReference β€” references a reusable library condition by ID

Operators: equals, contains, startsWith, endsWith, notEquals, matches (regex).

Verify after creation

Find the new rule by name
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq '.response[] | select(.rule.name | test("P16g")) | {
        name: .rule.name,
        rank: .rule.rank,
        state: .rule.state,
        profile: .profile,
        conditions: [.rule.condition.children[] | {dict: .dictionaryName, attr: .attributeName, op: .operator, val: .attributeValue}]
    }'

Authorization Rules β€” Update

Update requires the rule UUID. Get it from the rule listing.

Get rule UUID by name
RULE_ID=$(curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq -r '.response[] | select(.rule.name == "Domus_Cert_Admin_P16g") | .rule.id')
echo "Rule ID: ${RULE_ID}"
Disable a rule
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization/${RULE_ID}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -X PUT \
    -d "{
      \"rule\": {\"state\": \"disabled\"}
    }" | jq '.response.rule | {name, state}'

Authorization Rules β€” Delete

Delete by rule UUID
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization/${RULE_ID}" \
    -H "Accept: application/json" \
    -X DELETE | jq '.'

Endpoint Management

Endpoints can be blocked by ISE’s anti-RADIUS-spray protection. Failed auth attempts during configuration cause the MAC to be rejected β€” every subsequent attempt fails silently.

List rejected endpoints
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/rejectedendpoint" \
    -H "Accept: application/json" \
    | jq -r '
        ["MAC","ID"],
        (.SearchResult.resources[] | [.name, .id]) | @tsv
    ' | column -ts $'\t'
Release a rejected endpoint (requires endpoint ID, not MAC)
ENDPOINT_ID=$(curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/rejectedendpoint" \
    -H "Accept: application/json" \
    | jq -r '.SearchResult.resources[] | select(.name == "A8:2B:DD:8F:23:E6") | .id')

curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/rejectedendpoint/${ENDPOINT_ID}" \
    -H "Accept: application/json" \
    -X DELETE | jq '.'

DataConnect (Database Analytics)

DataConnect provides direct Oracle database access to ISE operational data β€” RADIUS authentication logs, active sessions, TACACS+ commands. This is not a REST API β€” it uses JDBC over TLS (port 2484, service cpm10). Use netapi ise dc commands.

Auth history for a MAC address (last hour)
netapi ise dc auth-history a8:2b:dd:8f:23:e6 --hours 1
Recent failed authentications
netapi ise dc auth-failures --hours 1
Raw SQL query against RADIUS authentications
netapi ise dc query "
SELECT mac_address, authentication_method, passed, timestamp
FROM radius_authentications
WHERE timestamp > SYSDATE - 1
ORDER BY timestamp DESC
"
TACACS+ authentication audit
netapi ise dc tacacs-auth --hours 24
TACACS+ command accounting
netapi ise dc tacacs-commands --hours 24

DataConnect environment variables: ISE_DATACONNECT_HOST, ISE_DATACONNECT_USER, ISE_DATACONNECT_PASS, ISE_DATACONNECT_CA. These are separate from the ERS credentials β€” DataConnect uses a dedicated database user, not the ERS API account. The CA cert is also different (ISE_DATACONNECT_CA vs ISE_CA_CERT).


MnT (Monitoring and Troubleshooting)

MnT provides real-time session data via REST/XML. Uses ERS credentials (ISE_MNT_USER/ISE_MNT_PASS, falls back to ISE_API_USER/ISE_API_PASS). Host: ISE_MNT_FQDN or ISE_PAN_FQDN.

Active session for a MAC
netapi ise mnt session a8:2b:dd:8f:23:e6
All active sessions (detailed)
netapi ise mnt sessions -d
MnT via curl (returns XML β€” convert with jq-compatible tools or parse directly)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/admin/API/mnt/Session/ActiveList" \
    -H "Accept: application/xml"
MnT session by MAC (replace colons with URL-safe format)
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/admin/API/mnt/Session/MACAddress/A8:2B:DD:8F:23:E6" \
    -H "Accept: application/xml"

MnT returns XML, not JSON. netapi ise mnt converts to table/JSON automatically. Raw curl responses need xmllint --format - or similar for readability.


pxGrid (Real-Time Event Streaming)

pxGrid 2.0 uses WebSocket over mTLS (port 8910). Certificate-based authentication β€” no username/password. Requires client cert registration with ISE.

Environment variables: ISE_PXGRID_FQDN, ISE_PXGRID_CERT, ISE_PXGRID_KEY, ISE_PXGRID_CA.

Subscribe to session changes (real-time)
netapi ise pxgrid sessions
ANC (Adaptive Network Control) β€” list policies
netapi ise pxgrid anc-policies
Apply ANC quarantine to an endpoint
netapi ise pxgrid anc-apply --mac A8:2B:DD:8F:23:E6 --policy Quarantine
Clear ANC policy from an endpoint
netapi ise pxgrid anc-clear --mac A8:2B:DD:8F:23:E6

pxGrid is not curl-friendly β€” it requires WebSocket upgrade, mTLS handshake, and STOMP protocol framing. Use netapi ise pxgrid for all pxGrid operations. The underlying client handles certificate negotiation, service lookup, and topic subscription automatically.


Dictionaries and Attributes

ISE conditions reference dictionaries and attributes. Use these to discover valid condition parameters.

List all available dictionaries
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/dictionaries" \
    -H "Accept: application/json" \
    | jq -r '.response[] | .name' | sort
List attributes for a specific dictionary
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/dictionaries/CERTIFICATE" \
    -H "Accept: application/json" \
    | jq -r '
        ["ATTRIBUTE","TYPE"],
        (.response.attributes[] | [.name, .dataType]) | @tsv
    ' | column -ts $'\t'

Common certificate attributes for EAP-TLS

Dictionary Attribute Use

Network Access

EapAuthentication

Match EAP method (EAP-TLS, PEAP, etc.)

CERTIFICATE

Subject - Common Name

Match cert CN (hostname identity)

CERTIFICATE

Subject - Organization

Match cert O field (org grouping)

CERTIFICATE

Subject - Organizational Unit

Match cert OU field (admin vs user role)

CERTIFICATE

Issuer - Common Name

Match issuing CA (trust validation)

Network Access

EapTunnel

Match tunnel type (TEAP)

Network Access

EapChainingResult

TEAP chaining result (user + machine)


jq Patterns for ISE Policy Analysis

Searching and filtering

Find which rule matches a specific cert CN
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq '.response[] | select(
        .rule.condition | recurse(.children[]?) | select(.attributeValue? | test("p16g"; "i"))
    ) | {name: .rule.name, rank: .rule.rank, profile: .profile[0]}'
All rules assigning a specific profile
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq '.response[] | select(
        .profile[] | test("Admin")
    ) | {name: .rule.name, rank: .rule.rank, hits: .rule.hitCounts}'

Extracting conditions

Extract all certificate-based conditions across rules
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/api/v1/policy/network-access/policy-set/${POLICY_SET_ID}/authorization" \
    -H "Accept: application/json" \
    | jq '.response[] | {
        rule: .rule.name,
        cert_conditions: [
            .rule.condition | recurse(.children[]?) |
            select(.dictionaryName? == "CERTIFICATE") |
            {attr: .attributeName, op: .operator, val: .attributeValue}
        ]
    } | select(.cert_conditions | length > 0)'

jq recurse + select pattern: ISE conditions are nested (AND blocks contain OR blocks contain attributes). recurse(.children[]?) walks the entire tree. select(.attributeName?) filters to leaf nodes with actual values. This pattern works regardless of nesting depth.


DACLs (Downloadable ACLs)

List all DACLs
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/downloadableacl?size=100" \
    -H "Accept: application/json" \
    | jq -r '
        ["NAME","ID"],
        (.SearchResult.resources[] | [.name, .id]) | @tsv
    ' | column -ts $'\t'
Get DACL content by name
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/downloadableacl/name/DACL_ADMIN_FULL" \
    -H "Accept: application/json" \
    | jq '.DownloadableAcl | {name, dacl, daclType}'

Network Access Devices (NADs)

List all NADs
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/networkdevice?size=100" \
    -H "Accept: application/json" \
    | jq -r '
        ["NAME","ID"],
        (.SearchResult.resources[] | [.name, .id]) | @tsv
    ' | column -ts $'\t'
Get NAD detail by name
curl -s --cacert "${ISE_CA_CERT/#\~/$HOME}" -u "${ISE_API_USER}:${ISE_API_PASS}" \
    "https://${ISE_PAN_FQDN}/ers/config/networkdevice/name/LAB-3560CX-01" \
    -H "Accept: application/json" \
    | jq '.NetworkDevice | {name, description, profileName, NetworkDeviceIPList}'