Cisco Secure Network Analytics API Client Code Examples¶
This guide shows how to use the
CiscoSNA client to interact with Cisco Secure Network Analytics APIs.
Environment Variables
You can set environment variables in your shell to avoid hardcoding sensitive information in your code. Check Environment Variables for details.
from wingpy import CiscoSNA
sna = CiscoSNA(
base_url="https://sna.example.com", # (1)!
username="...", # (2)!
password="...", # (3)!
tenant_name="...", # (4)!
verify=False,
)
-
Environment variable:
-
Environment variable:
-
Environment variable:
-
Environment variable:
If you have multiple tenants, you can specify the tenant name to use. If no tenant name is provided, the client will use the first/only available tenant for the user.
response = sna.get("/smc-users/rest/v1/user-context")
print(f"Username: {response['data']['userName']}")
Even though Secure Network Analytics does not use pagination you can still benefit from using the get_all method to retrieve all results from a list-based API call. Response data is usually placed in a data list element by the API. But for some API endpoints some cases list-data is nested further and in those cases get_all will extract and return the actual list so you can iterate over it directly.
host_group_tags = sna.get_all("/sw-reporting/v1/tenants/{tenantId}/customHosts/tags")
for tag in host_group_tags:
print(tag["displayName"])
Some Secure Network Analytics API calls are query-based, meaning they return an ID and you need to poll for the status of the result.
When the query status indicates that the job is complete, you can retrieve the results using the provided result ID and the path documented in the API.
Secure Network Analytics API has two different reporting APIs that work in this way, but their implementation details differ.
Handling version 1 queries manually¶
Tip
Use the wait_for method in the client to handle queries for you automatically.
Version 1 queries is created using a POST request to /sw-reporting/v1/tenants/{tenantId}/{query_path} which creates the job and returns a query ID.
We must then periodically poll /sw-reporting/v1/tenants/{tenantId}{query_path}/{queryId} to check the status of the job.
Once the status field changes to "COMPLETED", the results are available at /sw-reporting/v1/tenants/{tenantId}{result_path}/{queryId}/results.
Handling version 2 queries manually¶
Tip
Use the wait_for method in the client to handle queries for you automatically.
Version 2 queries is created using a POST request to /sw-reporting/v2/tenants/{tenantId}{query_path} which creates the job and returns a query ID.
{
"data": {
"query": {
"id": "6a7af7a8782f23084d65cfb2",
"domainId": "301",
"percentComplete": 8.33,
"status": "IN_PROGRESS"
}
}
}
We must then periodically poll /sw-reporting/v2/tenants/{tenantId}{query_path}/{queryId} to check the status of the job.
Once the status field changes to "COMPLETED", the results are available at /sw-reporting/v2/tenants/{tenantId}{query_path}/{queryId}/results.
Automatic v1/v2 query handling with wait_for¶
The wait_for method in the client handles queries for you, and simply returns the result path when the job is complete. You can then use get_all to retrieve the results.
query = {
"startDateTime": "2026-08-11T08:00:00Z",
"endDateTime": "2026-08-11T08:00:00Z",
}
flows_path = sna.wait_for(
sna.post,
"/sw-reporting/v2/tenants/{tenantId}/flows/queries",
data=query,
)
flows = sna.get_all(flows_path)
for flow in flows:
print(flow["peer"]["ipAddress"])
query = {
"startTime": "2026-08-11T08:00:00.000",
"endTime": "2026-08-11T09:00:00.000",
}
top_hosts = sna.wait_for(
sna.post,
"/sw-reporting/v1/tenants/{tenantId}/flow-reports/top-hosts/queries",
data=query,
on_complete=sna.get_all,
)
for host in top_hosts:
print(host["bytes"])