Foundations
What ASD is, and what it is not
ASD is one of the Cisco Support APIs: a REST (Representational State Transfer) API with JSON (JavaScript Object Notation) bodies that returns software metadata for a device and then a short-lived, per-session download URL for the image. It does what a person does on the software download site (pick a release, read the checksum, accept the license, click download), but from a script, a pipeline or an image-management tool.
/software/v4.0metadataTransId and of a download URLUse ASD when
- You run your own image repository or CI/CD (continuous integration and delivery) pipeline
- You need checksums and release metadata in a CMDB (configuration management database) or compliance report
- You build a tool for many platforms that no single controller manages
Prefer something else when
- The devices are already managed by Catalyst Center or Intersight: let the controller fetch the image
- You only need to know which release to run: Software Suggestion v2 answers that without a download
- The account has no SNTC or PSS entitlement: the calls will not be authorized
Foundations
Use cases
Six ways customers put ASD to work. Each card says who runs it, how often, the steps and what the customer gets at the end. Start with the first one: it is the base the others build on.
1. Keep an approved image repository current
Who: network automation or platform team · Runs: nightly or weekly
- Choose targets (Software Suggestion or your standards)
- Plan file of PIDs and targets
- ASD metadata and download
- SHA-512 check
- File and .sha512 into the repository
Outcome: every platform in the estate has its approved image on an internal server, already verified, before anyone opens a change. Script: asd_batch.py.
2. Build the upgrade kit for a change request
Who: change owner or NOC (network operations center) · Runs: per change
/metadata/pidreleasefor the affected PIDs- Collect release, size, SHA-512, minimum DRAM and flash
- Add release-note and advisory links
- Attach to the ticket
Outcome: the change record carries the exact file, checksum and memory prerequisites, so reviewers approve against facts and engineers stage the same file that was approved.
3. Audit images already in the field
Who: security or compliance · Runs: monthly or after an incident
- Export image file names and hashes from inventory
/metadata/images, five names per call- Compare SHA-512, flag
isDeleted - For advisories,
/metadata/pidimageper PID
Outcome: a report of devices running images Cisco has removed from download, any file whose hash does not match Cisco's published value and, from the per-PID call, images with a software advisory, deferral notice or PSIRT flag.
4. Stage software for an air-gapped or high-security site
Who: OT (operational technology), government or regulated sites · Runs: per release
- Download and verify in a connected zone
- Carry file and .sha512 across the gap
- Re-verify with
sha512sum -cinside
Outcome: a documented chain of custody: the hash checked on the inside is the hash Cisco published.
5. Feed lifecycle data to other tools
Who: CMDB, NetBox or ServiceNow owners · Runs: daily
- Metadata per PID
- Store
isSuggested,lifeCycle,psirtIndicator, advisories,fcsDate - Join to inventory
Outcome: dashboards that show which platforms are behind the suggested release or carry a security advisory, without anyone browsing the download site.
6. Cover platforms no controller manages
Who: teams with mixed estates (firewalls, routers, optics, appliances) · Runs: as needed
Catalyst Center and Intersight fetch images for what they manage. ASD covers the rest with one workflow, so the repository and audit in use cases 1 and 3 can include every Cisco platform the contract covers.
Foundations
Claim check: what circulating write-ups get wrong
A widely shared AI-generated summary of this API had the concept right and most of the specifics wrong. The table compares its claims with Cisco's v4.0 reference. If you inherited code or slides built from that summary, these are the places to fix.
| Claim in the summary | Verdict | What the v4.0 reference says |
|---|---|---|
| ASD is part of the Cisco Support APIs on DevNet | Correct | Listed first in the Support APIs portfolio. |
Token from id.cisco.com/oauth2/default/v1/token, client credentials grant | Correct | Same endpoint and grant. The older cloudsso.cisco.com/as/token.oauth2 applies only to apps registered before 1 March 2023 and is being deprecated. |
| Needs SNTC or PSS, registered in the API Console | Correct | Smart Net Total Care customers and Partner Support Service partners only; the API user also needs the API Developer role. |
| "Internal Cisco engineering entitlements" grant access | Unsupported | No Cisco documentation says so. The API Console does list an "Automated Software Distribution Preview-V3" entry (released 21 Nov 2024) with a Request Access button and no documentation; requests go to swc-it-support@cisco.com. |
GET /software/releases/v1/pid/{pid} | Wrong | POST /software/v4.0/metadata/pidrelease with a JSON body. The PID goes in the body, not the path. |
GET /software/image/v1/imageName/{name} | Wrong | POST /metadata/pidimage (PID plus 1–5 image names) or POST /metadata/images (names only). |
GET /software/download/v1/image/{name}/eulaAccept/true | Wrong | POST /download/pidimage with pid, mdfId, imageGuids and metadataTransId. EULA and K9 acceptance are separate /compliance/eula and /compliance/k9 calls. |
Response {"downloadUrl", "imageName", "expiryTime"} | Wrong | downloads[] entries with url, token, imageGuid, imageName, exception[], plus a top-level sessionId. No expiry field; the URL lives 60 minutes. |
| Checksums come with the image-details call | Partly | MD5 and SHA-512 come from the three metadata calls, never from the download call. |
| ASD returns Gold Star / suggested releases | Partly | ASD flags isSuggested per release. Ranked suggestions come from the separate Software Suggestion v2 API. |
Catalyst Center POST /dna/intent/api/v1/image/importation/source/cisco | Wrong | No such path. Imports are /image/importation/source/url and /source/file; cisco.com images use /images/ccoSync then /images/{id}/download. |
Intersight firmware/Distributables and firmware/Upgrades also upgrade Nexus fabric | Partly | Both objects exist and drive UCS (Unified Computing System) server and fabric-interconnect firmware. Nothing found supports Nexus switch upgrades through them. |
Foundations
Entitlement and onboarding
Access is gated twice: once to reach the API at all, and again on every download, against the contracts on the Cisco.com profile behind the app. Most failed ASD projects stall here, not in code.
- SNTC or PSS contract
- API Developer role (CSAM)
- Register app in API Console
- Add "Automated Software Distribution"
- Contracts on the Cisco.com profile
- Software download access (ART)
| Step | Customer (SNTC) | Partner (PSS) |
|---|---|---|
| 1. Entitlement | Smart Net Total Care. Complete the SNTC portal onboarding guide. | Partner Support Service. The partner must hold at least one valid SNTC contract with the customer organization it acts for. |
| 2. API role | The company's Delegated Administrator grants the API Developer role in CSAM (Cisco Services Access Management). | Request access to PSS APIs and the API Console from the PSS community page, quoting a PSS contract number. A TAC engineer grants it; allow up to 48 hours. |
| 3. App registration | Cisco API Console (apiconsole.cisco.com) > My Apps & Keys > Register a New App > OAuth 2.0 grant Client Credentials only > select the Support APIs. The Client ID and Secret do not expire but can be regenerated; treat them like a password. | |
| 4. ASD visible? | ASD must appear under Select APIs on the Register a New App form before your app can be given access. If it is missing, the role or entitlement is not in place yet. The console's documentation list also has an "Automated Software Distribution Preview-V3" entry (released 21 Nov 2024, no documentation) with a Request Access button; ask swc-it-support@cisco.com which entry applies to you before requesting. | |
| 5. Download entitlement | Each registration carries the identity and permissions of the API user who created it. Images that need a contract return metadata but no URL until the contract is on that user's Cisco.com profile (Profile Manager). | |
| 6. Software download access | Contract-registered software can return IAC_ERROR until the user is granted Software Download Access through Cisco's ART access-request site (edsart.cloudapps.cisco.com): Cisco Service > Connected Experience (CX) > Delivery & Tools Support > Software Download and Special File Publishing Access. | |
Use a dedicated Cisco.com identity for automation. Downloads are authorized against the profile behind the app, so a personal login means the pipeline breaks when that person leaves or their contract associations change.
Foundations
Authentication
One OAuth 2.0 client-credentials request returns a Bearer token that every Support API accepts. The token lasts 3,600 seconds by default; cache it and renew a few minutes early rather than per call.
curl -s -X POST https://id.cisco.com/oauth2/default/v1/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$CISCO_CLIENT_ID" \
--data-urlencode "client_secret=$CISCO_CLIENT_SECRET"
# 200 OK
# {"access_token": "Er2cdpFDGNsQ...", "token_type": "Bearer", "expires_in": 3599}| Item | Detail |
|---|---|
| Token endpoint | POST https://id.cisco.com/oauth2/default/v1/token, form-encoded grant_type, client_id, client_secret |
| API host | apix.cisco.com. Older posts and code use api.cisco.com, which was replaced in the same migration. |
| Header | Authorization: Bearer <access_token> and Content-Type: application/json for the POST bodies |
| Legacy endpoint | cloudsso.cisco.com/as/token.oauth2: apps registered before 1 March 2023 only, being deprecated. The API Console's Migrating Applications page says to re-register those apps (new Client ID and Secret), switch to the id.cisco.com token URL, and change api.cisco.com to apix.cisco.com. |
| Download links | The same access token is appended to non-cloud download URLs as &access_token=. Keep it out of logs. |
Workflow
Deploy it in five steps
For a customer standing up ASD automation for the first time. Steps 1 and 2 are paperwork and can take a few days; steps 3 to 5 take an afternoon.
Step 1 · Confirm access
Check the customer has SNTC (or works through a PSS partner) and that the automation's Cisco.com identity has the API Developer role and the right contracts on its profile. See Entitlement and onboarding.
Done when: "Automated Software Distribution" is selectable on the API Console's Register a New App form.
Step 2 · Register the app
API Console > My Apps & Keys > Register a New App. Application type Service, grant type Client Credentials, APIs: Automated Software Distribution and Software Suggestion API V2.
Done when: you have a Client ID and Client Secret.
Step 3 · Store the secret and test one PID
Put the ID and secret in the customer's secrets store (vault, CI variables), never in code. Run the Python client against one PID the customer owns.
pip install requests
export CISCO_CLIENT_ID=… CISCO_CLIENT_SECRET=…
python asd_client.py C9300-48P 17.9.4Done when: the image downloads and prints "SHA-512 verified". If it prints exception codes instead, look them up in Errors and exceptions.
Step 4 · Write the plan file and run the batch
One row per platform: the PID, the release it runs today, and the target. The batch script downloads each approved image once, verifies it, writes a .sha512 file beside it, and prints a JSON report. It exits non-zero if anything was blocked or failed, so a scheduler can alert.
pid,current_release,target
C9300-48P,17.9.4,latest
C9500-48Y4C,17.9.4,17.12.6
ISR4451-X/K9,17.6.5,above# asd_batch.py: nightly refresh of an image repository from a plan file
# plan.csv columns: pid,current_release,target (target = latest | above | a release such as 17.12.6)
import csv, json, os, sys, time
from asd_client import ASDClient
REPO = os.environ.get("ASD_REPO", "./images")
os.makedirs(REPO, exist_ok=True)
c = ASDClient(os.environ["CISCO_CLIENT_ID"], os.environ["CISCO_CLIENT_SECRET"])
report = []
for row in csv.DictReader(open(sys.argv[1])):
pid, cur, tgt = row["pid"], row["current_release"], row.get("target") or "latest"
try:
meta = c.metadata_by_release(pid, cur, tgt)
rows = list(c.images(meta))
ok = [r for r in rows if not r["exceptions"]]
if not ok: # metadata came back, but every image is gated
report.append({"pid": pid, "status": "blocked",
"codes": sorted({e for r in rows for e in r["exceptions"]})})
continue
pick = ok[0]
dest = os.path.join(REPO, pick["name"])
if os.path.exists(dest):
report.append({"pid": pid, "status": "already in repo", "image": pick["name"]}); continue
d = c.download_urls(pid, pick["mdfId"], [pick["guid"]], meta["metadataTransId"])
item = d["downloads"][0]
if item.get("exception"):
report.append({"pid": pid, "status": "blocked",
"codes": [e.get("code") for e in item["exception"]]}); continue
sha = c.fetch(item, dest + ".part")
if pick["sha512"] and sha.lower() != pick["sha512"].lower():
os.remove(dest + ".part")
report.append({"pid": pid, "status": "checksum mismatch", "image": pick["name"]}); continue
os.rename(dest + ".part", dest)
with open(dest + ".sha512", "w") as f:
f.write(f'{pick["sha512"]} {pick["name"]}\n')
report.append({"pid": pid, "status": "downloaded", "image": pick["name"], "release": pick["release"]})
except Exception as e: # one bad PID must not stop the run
report.append({"pid": pid, "status": "error", "detail": str(e)[:200]})
time.sleep(2) # stay well under the per-second limit
print(json.dumps(report, indent=2))
sys.exit(1 if any(r["status"] in ("blocked", "error", "checksum mismatch") for r in report) else 0)
Tested against the same local mock as the client: download, verification, and skip-if-present on a second run.
Step 5 · Schedule it and watch the report
Run nightly from cron or the CI system, keep the JSON report, and alert on blocked, error or checksum mismatch. Blocked usually means a contract, EULA or K9 action for a person, not a code fix.
15 2 * * * cd /opt/asd && ASD_REPO=/srv/images python3 asd_batch.py plan.csv > report-$(date +\%F).json 2>&1 || /opt/asd/alert.shDone when: a night's run leaves new images and a clean report, and a forced failure (a bad PID) raises an alert.
Workflow
End-to-end flow
From token to verified file: three API calls and a file download, plus one or two compliance calls if a license gate is open. Step through to see each request and response; the packet follows the call you select.
metadataTransId. Step 5 happens only when the metadata or download response asks for it.Workflow
Find images: the three metadata calls Read only
All three return the image names, sizes and checksums. The first two also return the metadataTransId and mdfId (Cisco's product catalog ID, from the Metadata Framework) that the download call needs. Pick the call by what you already know.
| Operation | You know | Body (fields as in Cisco's samples) | Returns a metadataTransId? |
|---|---|---|---|
POST /software/v4.0/metadata/pidrelease | The PID and its current release | pid, currentReleaseVersion, outputReleaseVersion (latest, above or a specific release), pageIndex, perPage (max 25) | Yes |
POST /software/v4.0/metadata/pidimage | The PID and the exact image file names | pid, imageNames (array, 1–5), pageIndex, perPage. Unknown names come back in invalidImages | Yes |
POST /software/v4.0/metadata/images | Only file names (for example from a device inventory) | imageNames (array, 1–5) | No: status, dates, size and checksums only |
POST https://apix.cisco.com/software/v4.0/metadata/pidrelease
Authorization: Bearer <access_token>
Content-Type: application/json
{
"pid": "C9300-48P",
"currentReleaseVersion": "17.9.4",
"outputReleaseVersion": "latest",
"pageIndex": "1",
"perPage": "25"
}name, size, version and lifeCycle where the parameter tables say imageName, imageSize, releaseVersion and lifecycle: read both.Always inspect exception[ ]
A metadata call can return HTTP 200 with an exception code on an image, such as IMG_CONTRACT_REQD or IMG_K9. The metadata is real, but no download URL will follow until the cause is fixed.
Signals worth storing
isSuggested, lifeCycle, psirtIndicator (Product Security Incident Response Team advisory attached), softwareAdvisory, deferralNotice, isDeleted, additionalEntitlement.
PID format
One PID per call. Cisco's example shows a full UDI-style value (ACS-1800-RM-19=VID:V01); a base PID such as C9300-48P is the usual input. If you get NO_DATA_FOUND_FOR_PID, check the PID and try the base PID without suffixes.
Workflow
EULA and K9 gates
Some images need a signed EULA, and strong-encryption images need the K9 export form. You read the current text with a GET and record acceptance with a POST. The gates show up as exception codes (EULA_FORM_AR, K9_FORM_AR, K9_EULA_FORM_AR, K9_IMG_DWLD) or as eulaContent and k9Content in the download response.
| Operation | Purpose | Body |
|---|---|---|
GET /compliance/eula | Current EULA text, accept and decline values, webForm link, subAppVersion | None |
POST /compliance/eula | Record acceptance or decline | status (Accepted | Declined), fileNames, declineComments if declined |
GET /compliance/k9 | K9 form fields and values, user details, webForm link | None |
POST /compliance/k9 | Record the K9 answers | status, busFunction (COMM_OR_CIVIL), confirm (CONFIRM_CHECKED), govMilCountries, fileNames (one), declineComments if declined |
These are legal attestations, not plumbing. A POST to /compliance/k9 certifies export-control answers for the organization, on behalf of the Cisco.com identity behind the app. Have the person entitled to make that statement accept it once, interactively (the webForm links to software.cisco.com/download/k9 and /eula), and do not hard-code acceptance into an unattended pipeline. A rejected K9 (K9_REJECTED) is reviewed by Cisco; the documented retry window is about four hours.
Workflow
Get the file Leaves the API tier
POST /download/pidimage turns up to five image GUIDs into sessionalized URLs. It returns no checksum: keep the SHA-512 from the metadata call.
POST https://apix.cisco.com/software/v4.0/download/pidimage
Authorization: Bearer <access_token>
Content-Type: application/json
{
"pid": "ACS-1800-RM-19=",
"mdfId": "286305578",
"metadataTransId": "617462102359722937",
"imageGuids": ["25856C5890AE73F8EDBEEDA441EC901F8FC8362E"]
}
# 200 OK (abridged from Cisco's sample)
{
"sessionId": "205785277984030082",
"downloads": [{
"url": "https://…/download.cgi?dwnld_code=…",
"token": "",
"imageGuid": "25856C5890AE73F8EDBEEDA441EC901F8FC8362E",
"imageName": "n9000-epld.7.0.3.I7.9.img",
"exception": []
}]
}token field | Where the image is | How to fetch it |
|---|---|---|
| Empty | Default download server | Append &access_token=<your API token> to url and request it (the guide's client uses GET). |
| Set | Cisco cloud store | POST to url with Content-Type: application/x-www-form-urlencoded and body X-Authentication-Control=<token>. Follow one or more HTTP 302 redirects. |
# Default URL (token field empty)
curl -fL -o "$IMAGE" "$URL&access_token=$ACCESS_TOKEN"
# Cloud URL (token field set): form POST, follow redirects
curl -fL -o "$IMAGE" -X POST "$URL" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "X-Authentication-Control=$CLOUD_TOKEN"
# Compare with the sha512 from the metadata call
echo "$SHA512 $IMAGE" | sha512sum -c -Cisco's own cloud example passes -k, which turns off certificate checks. Leave it out and keep verification on: a software image is exactly what you do not want intercepted or swapped.
Workflow
Request builder
Fill in what you know; the builder writes the matching calls with the body fields spelled as in Cisco's samples. Nothing leaves this page.
Your device and target
Target is latest, above, or a specific release such as 17.12.6. With image names, the builder uses /metadata/pidimage instead.
Workflow
Python client
A complete client: token caching with early renewal, the three metadata shapes flattened into rows, exception-aware selection, both download modes, streamed SHA-512 verification, and backoff on the 403 rate-limit responses ASD uses instead of 429. It was run end to end against a local mock of the documented request and response shapes (token, metadata, a K9-blocked image skipped, download URL, 302 redirect, checksum). It has not been run against Cisco's production API.
requests)# asd_client.py: Cisco Automated Software Distribution (ASD) API v4.0 client
# token cache, metadata lookup, EULA/K9 check, download URL, streamed download, SHA-512 check
import hashlib, os, sys, time, requests
TOKEN_URL = "https://id.cisco.com/oauth2/default/v1/token"
ASD = os.environ.get("ASD_BASE", "https://apix.cisco.com/software/v4.0")
class ASDClient:
def __init__(self, client_id, client_secret, token_url=TOKEN_URL, base=ASD):
self.cid, self.sec, self.token_url, self.base = client_id, client_secret, token_url, base
self.s = requests.Session(); self.tok = None; self.exp = 0
def token(self):
if time.time() < self.exp:
return self.tok
r = self.s.post(self.token_url, data={"grant_type": "client_credentials",
"client_id": self.cid, "client_secret": self.sec}, timeout=30)
r.raise_for_status(); j = r.json()
self.tok = j["access_token"]
self.exp = time.time() + int(j.get("expires_in", 3600)) - 300 # renew 5 min early
return self.tok
def post(self, path, body):
for attempt in range(4):
r = self.s.post(self.base + path, json=body, timeout=60,
headers={"Authorization": f"Bearer {self.token()}"})
# The ASD error table reports rate and quota limits as 403, not 429
if r.status_code in (403, 429, 502, 503, 504) and attempt < 3:
if r.status_code == 403 and "Rate" not in r.text and "Over" not in r.text:
break # a real permission error: stop
time.sleep(2 ** attempt * 5); continue
break
if r.status_code >= 400:
raise RuntimeError(f"{path} -> HTTP {r.status_code}: {r.text[:300]}")
return r.json()
@staticmethod
def images(meta):
"""Flatten metadata -> products -> softwareTypes -> operatingSystems -> releases -> images."""
for m in meta.get("metadata", []):
for p in m.get("products", []):
for st in p.get("softwareTypes", []):
for os_ in st.get("operatingSystems", []):
for rel in os_.get("releases", []):
for img in rel.get("images", []):
yield {"pid": m.get("pid"), "mdfId": p.get("mdfId"),
"release": rel.get("version") or rel.get("releaseVersion"),
"suggested": rel.get("isSuggested"),
"name": img.get("name") or img.get("imageName"),
"guid": img.get("imageGuid"),
"size": img.get("size") or img.get("imageSize"),
"sha512": img.get("sha512"), "md5": img.get("md5"),
"exceptions": [e.get("code") for e in img.get("exception", [])]}
def metadata_by_release(self, pid, current, output="latest", page=1):
# Field casing follows Cisco's sample request; the parameter table spells some differently
return self.post("/metadata/pidrelease", {"pid": pid, "currentReleaseVersion": current,
"outputReleaseVersion": output, "pageIndex": str(page), "perPage": "25"})
def metadata_by_image(self, pid, image_names):
return self.post("/metadata/pidimage", {"pid": pid, "imageNames": image_names[:5],
"pageIndex": "1", "perPage": "25"})
def accept(self, kind, file_name):
# kind is "eula" or "k9"; only call after reviewing the agreement with the right owner
body = {"status": "Accepted", "fileNames": file_name}
if kind == "k9":
body.update({"busFunction": "COMM_OR_CIVIL", "confirm": "CONFIRM_CHECKED"})
return self.post(f"/compliance/{kind}", body)
def download_urls(self, pid, mdf_id, guids, trans_id):
return self.post("/download/pidimage", {"pid": pid, "mdfId": str(mdf_id),
"imageGuids": guids[:5], "metadataTransId": trans_id})
def fetch(self, item, dest):
"""Stream one entry of downloads[] to disk; returns the SHA-512 of the bytes written."""
h = hashlib.sha512()
if item.get("token"): # image is in Cisco's cloud store: form-encoded POST, follow 302s
r = self.s.post(item["url"], data={"X-Authentication-Control": item["token"]},
stream=True, allow_redirects=True, timeout=600)
else: # default download URL: append the API access token
r = self.s.get(item["url"] + "&access_token=" + self.token(),
stream=True, allow_redirects=True, timeout=600)
r.raise_for_status()
with open(dest, "wb") as f:
for chunk in r.iter_content(1 << 20):
f.write(chunk); h.update(chunk)
return h.hexdigest()
if __name__ == "__main__":
pid, current = sys.argv[1], sys.argv[2]
c = ASDClient(os.environ["CISCO_CLIENT_ID"], os.environ["CISCO_CLIENT_SECRET"])
meta = c.metadata_by_release(pid, current, "latest")
trans = meta["metadataTransId"] # valid for 60 minutes
imgs = list(c.images(meta))
for i in imgs:
print(f'{i["release"]:<14} {i["name"]:<48} {i["size"]:>12} {",".join(i["exceptions"]) or "ok"}')
ok = [i for i in imgs if not i["exceptions"]]
if not ok:
sys.exit("No downloadable image: resolve the exception codes above first")
pick = ok[0]
d = c.download_urls(pid, pick["mdfId"], [pick["guid"]], trans)
item = d["downloads"][0]
if item.get("exception"):
sys.exit(f'Download blocked: {[e.get("code") for e in item["exception"]]}')
got = c.fetch(item, item["imageName"])
if pick["sha512"] and got.lower() != pick["sha512"].lower():
os.remove(item["imageName"]); sys.exit("SHA-512 mismatch: file deleted")
print(f'{item["imageName"]} downloaded and SHA-512 verified')
pip install requests
export CISCO_CLIENT_ID=… CISCO_CLIENT_SECRET=…
python asd_client.py C9300-48P 17.9.4
# 17.12.6 cat9k_iosxe.17.12.06.SPA.bin … ok
# cat9k_iosxe.17.12.06.SPA.bin downloaded and SHA-512 verifiedCompanions
Software Suggestion v2: which release?
ASD says what exists and lets you download it. Software Suggestion says what Cisco recommends, based on stability, longevity, adoption rate and other factors. Use it first to choose the target, then hand the release to ASD. All operations are GET on https://apix.cisco.com/software/suggestion/v2/suggestions/…, with the same Bearer token, once the app has access to "Software Suggestion API V2".
| Path | Returns |
|---|---|
/software/productIds/{productIds} | Suggested releases and their images for a list of PIDs |
/releases/productIds/{productIds} | Suggested releases without images |
/compatible/productId/{basePID} | Compatible and suggested releases for one PID, filterable by currentImage, currentRelease, supportedFeatures |
/software/mdfIds/{mdfIds}, /releases/mdfIds/{mdfIds}, /compatible/mdfId/{mdfId} | The same three views keyed by MDF ID |
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://apix.cisco.com/software/suggestion/v2/suggestions/releases/productIds/C9300-48P,C9500-48Y4C?pageIndex=1"Community threads report empty or wrong suggestions for some PIDs (retired platforms, some Nexus and Catalyst 9500 PIDs, and a 5508 wireless controller case). Treat a suggestion as input to a decision, and cross-check it against release notes and field notices before it drives an automated upgrade.
Companions
Product Information: getting the MDF ID
The download call needs the mdfId. The metadata calls already return it, so you rarely need this, but the Product Information API maps PIDs to MDF IDs directly, which helps when you key a repository by MDF ID or call Software Suggestion by MDF ID.
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://apix.cisco.com/product/v1/information/product_ids_mdf/ASA5505-50-BUN-K9?page_index=1"
# product_list[0].product_name_mdf -> MDF ID of the product
# product_list[0].product_series_mdf -> MDF ID of the seriesNote the snake_case here (page_index, product_list) against camelCase in ASD and Software Suggestion: each Support API has its own naming.
Companions
Catalyst Center and Intersight
When a controller manages the devices, let it fetch and stage images through its own cisco.com connection; you automate the controller rather than ASD.
| Platform | Get images from cisco.com | Distribute and activate |
|---|---|---|
| Catalyst Center 2.3.7.x and 3.x | POST /dna/intent/api/v1/images/ccoSync (rate limited; the spec lists 2 per hour), then GET /dna/intent/api/v1/images?imported=false to list them, then POST /dna/intent/api/v1/images/{id}/download. Cisco's Ansible SWIM (Software Image Management) workflow module supports cisco.com import from 2.3.7.6. | From 2.3.7.9, the networkDeviceImages family (readiness checks, bulk distribute and activate). The older /image/distribution and /image/activation/device still answer but were marked Sunset in 3.1.3. Local imports: /image/importation/source/url and /source/file. |
| Intersight (UCS) | Firmware bundles come from the Intersight software repository; the API object is firmware/Distributables. | POST /api/v1/firmware/Upgrades for servers; fabric-interconnect upgrades in Intersight Managed Mode. Scope is UCS servers and fabric interconnects. |
The SWIM details for Catalyst Center are in the companion Catalyst Center API field guide on CiscoSE.
Companions
Which path?
What are you trying to do?
Pick a goal
Each answer names the API, the calls and the catch.
Operate
Errors and exceptions
ASD reports problems in two ways. HTTP errors (400, 401, 403, 5xx) mean the call itself failed. Exception codes inside a 200 response mean the call worked but this image cannot be downloaded yet. Code that only checks the status code will miss the second kind.
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
Not Authorized | 403 | Token invalid, or API key not recognized | Get a new token; check the app has ASD access in the API Console |
Account Over Queries Per Second Limit | 403 | Too many calls in one second | Back off and serialize; this is ASD's rate-limit signal, not 429 |
Account Over Rate Limit | 403 | Too many calls in the quota period | Slow down; check usage under Keys in the API Console |
Account Inactive | 403 | Key not approved or disabled | Contact the Support API team |
PROD_REG_NA | 401 | Product must be registered and approved for the service | Email swc-it-support@cisco.com |
PROD_REG_AV | 401 | This client ID cannot call the service | Register a new client ID; contact swc-it-support@cisco.com |
DNAC_REG_REQ | 401 | App must be registered for the service | Contact swc-it-support@cisco.com |
SW_NO_LONGER_AVL | 401 | Software for this product is no longer available | Platform is retired from the download site |
INVALID_OUTPUT_RELEASE | 401 | Output release empty | Send outputReleaseVersion |
PID_INVALID · PID_MISSING | 400 | PID invalid or absent | Check spelling and the pid field name |
NO_DATA_FOUND_FOR_PID | 400 | No software for that PID | Try the base PID; confirm on the download site |
CUR_REL_MISSING · OUT_REL_MISSING | 400 | Current or output release absent | Send both release fields |
IMG_NM_MISSING · IMG_NM_INVALID | 400 | Image names absent or invalid | Send imageNames as an array of exact file names |
IMAGE_LIMIT_EXCEEDED | 400 | Too many image names or GUIDs | Five per call |
MDFID_MISSING · MDFID_INVALID | 400 | MDF ID absent or invalid | Use mdfId from the same metadata response |
IMAGE_GUID_MISSING · IMAGE_GUID_INVALID | 400 | Image GUID absent or invalid | Use imageGuid from the same metadata response |
MTRANSID_MISSING · INVALID_MTRANSID | 400 | Transaction ID absent or invalid | Send metadataTransId from a metadata call |
MTRANSID_EXPIRED | 400 | Transaction ID older than 60 minutes | Re-run the metadata call, then download |
INVALID_INPUT | 400 | Invalid input or no data found | Validate the body against the Swagger file |
Service Not Found | 596 | Service missing, often spaces in parameters | Trim inputs |
SER_UNEXPECT_FAIL | 500 | Unexpected service failure | Retry later; report with the request data |
API Maintenance/Service Unavailable | 503 | Maintenance | Retry with backoff |
IMG_CONTRACT_REQD | 200 | Contract-registered image: metadata only, no URL | Add the covering contract to the Cisco.com profile (Profile Manager) |
CONTRACT_NOT_AUTH · CONTRACT_REJECTED | 200 | Contracts on the profile do not cover this product | Associate the right contract, or ask the account team or partner |
CONTRACT_LOGIN · CONTRACT_IMG_REQ · CONTRACT_REQ_DWLD · CONTRACT_REQD_DWLD · CONTRACT_IMG_DWLD | 200 | A valid service contract is required | Same as above |
IAC_ERROR · CONTRACT_ACCESS | 200 | No access to download contract-registered software | Request Software Download Access in ART |
IMG_K9 | 200 | Strong-encryption image; download not approved | Complete the K9 form; questions to tradeopscpr@cisco.com |
K9_IMG_DWLD · K9_FORM_AR · K9_FORM_ACC | 200 | K9 form not yet accepted | Accept K9 (see EULA and K9 gates) |
EULA_FORM_AR · EULA_FORM_ACC · K9_EULA_FORM_AR | 200 | EULA (and possibly K9) not yet accepted | Accept EULA, then K9 if listed |
K9_REJECTED | 200 | K9 answers under review or rejected | Retry after about 4 hours; tradeopscpr@cisco.com |
IP_CHECK_FAIL | 200 | Request from a territory not authorized to receive Cisco products | Check egress location; tradeopscpr@cisco.com |
LOGIN_REQD · LOGIN_IMG_DWLD · LOGIN_CONTRACT_REQ | 200 | A Cisco.com login (with contract) is required | The identity behind the app lacks the profile setup |
CPR_ADDRESS_EXCEPTION_MSG | 200 | Profile is missing a full address | Complete the address in Profile Manager |
C3_USERID_NMAP | 200 | User ID not mapped in C3 (a Cisco back-end system) | Contact Cisco support |
SW_ADV_IMAGE · DEF_ADV_IMAGE | 200 | Software or deferral advisory on the image | Read the advisory before using the image |
DWLD_WARN · DWLD_WARN1 · DWLD_WARN2 | 200 | You may not be authorized for the product | Check contract coverage; ent-dl@cisco.com |
Operate
Quotas and limits
| Limit | Value | Source |
|---|---|---|
| Records per metadata page | 25 | ASD reference |
| PIDs per metadata call | 1 | ASD reference |
| Image names or GUIDs per call | 1–5 | ASD reference |
metadataTransId and download URL life | 60 minutes | ASD reference |
| Access token life | 3,600 seconds by default | Support APIs authentication page |
| Calls per second and per day | Not in the ASD reference | The API Console's Register a New App form shows each API's limits next to its name; ASD's appear there once your account can select it. Exceeding them returns 403 (Over Queries Per Second, Over Rate Limit). Usage per key is under Keys. |
For scale, the same form shows 5 per second and 60 per minute for the PSIRT openVuln API, and 10 per second and 5,000 per day for the CX Cloud APIs; community reports cite 5,000 per day for EoX (End of Life). None of these is an ASD number: design for a few calls per minute and cache metadata.
Operate
Documentation quirks
The v4.0 reference contradicts itself in places. Where it does, this guide follows the sample requests and recommends checking the Swagger YAML (downloadable from the API Console) for your account.
| Where | Table says | Sample uses |
|---|---|---|
/metadata/pidrelease request | PID, OutputReleaseVersion, perpage, target Latest | pid, outputReleaseVersion, perPage, latest |
| Metadata responses | imageName, imageSize, releaseVersion, lifecycle, fieldNoticeUrl | name, size, version, lifeCycle, fieldNotice |
/metadata/images request | imageNames described as GUIDs | Image file names |
/compliance/k9 request | busfunction, confirm = Confirm_Checked, declineComments typed int | busFunction, CONFIRM_CHECKED, text |
/compliance/eula request | declineComments described as a download session ID | Free text |
| Hosts in samples | — | api-stage.cisco.com and dl-stage.cisco.com appear in selfLink and URLs: Cisco's stage environment. Production is apix.cisco.com. |
| Older posts | — | api.cisco.com/software/… and cloudsso.cisco.com: pre-2023 hosts |
Operate
Guidance checklist
- Confirm entitlement first: SNTC or PSS, API Developer role, ASD visible in the API Console, contracts on the profile, ART software download access.
- Use a dedicated automation identity, not a person's Cisco.com login.
- Cache the token and renew it about five minutes before
expires_in. - Pick the target with Software Suggestion, download with ASD.
- Check
exception[]on every 200. No URL follows until it is empty. - Finish the download inside 60 minutes of the metadata call; on
MTRANSID_EXPIREDstart again from metadata. - Never automate K9 or EULA acceptance silently. Have the accountable person accept once.
- Verify SHA-512 before an image enters the repository; delete on mismatch.
- Keep TLS (Transport Layer Security) verification on and keep tokens out of logs and URLs you store.
- Treat 403 as possibly a rate limit: read the message, back off, retry a few times.
- Prefer the controller when Catalyst Center or Intersight already manages the devices.
- Validate field names against the Swagger YAML for your account before production.
Operate
Figure index
Operate
Sources
- Automated Software Distribution API reference (v4.0): all eight operations, error codes, cloud download
- Introduction to Cisco Support APIs: portfolio
- Support APIs user onboarding process: SNTC and PSS access
- Support APIs application registration: API Console, client credentials
- Support APIs authentication: token endpoint and lifetime
- Software Suggestion API v2
- Product Information API: PID to MDF ID
- Cisco Community: legacy cloudsso endpoint for apps before 1 March 2023
- Cisco Community: ASD takes the PID in the body (400 otherwise)
- Catalyst Center: initiate sync of images from Cisco.com and download the software image
- Catalyst Center Software Image Management guide
- Ansible swim_workflow_manager module: cisco.com import from 2.3.7.6
- Intersight Managed Mode: managing firmware
- Cisco API Console: Migrating Applications: token URL and host changes
- Cisco API Console: Automated Software Distribution Preview-V3 listing (sign-in required)
- Cisco API Console, Register a New App form: per-API rate limits (sign-in required)