CiscoSEField reference

Field guide · Automated Software Distribution API v4.0 · Cisco Support APIs

Cisco Automated Software Distribution API

Download Cisco software from a script instead of the website: get API access, find the right image for a device, clear any license gates, then fetch the file and verify its checksum. It also covers when Catalyst Center or Intersight should do the job instead.

Scope: ASD (Automated Software Distribution) v4.0 at apix.cisco.com/software/v4.0, plus the companion Software Suggestion v2 and Product Information APIs.

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.

8operations, all under /software/v4.0
60 minlife of a metadataTransId and of a download URL
1–5image GUIDs (Globally Unique Identifiers) per download call
3,600 sdefault OAuth 2.0 access-token lifetime
Your pipeline or scriptPython, Ansible, CI/CD job Cisco identity serviceid.cisco.comOAuth 2.0 client credentials ASD API v4.0apix.cisco.com/software/v4.0metadata · compliance · downloadentitlement checked per call Companion Support APIsSoftware Suggestion v2Product Information(which release, which MDF ID) Cisco download serverssessionalized URL, 60 minutescloud store: one or more 302s Your image repositorySHA-512 verified before use Network devicesyour upgrade tooling installs Controllers fetch on their ownCatalyst Center: ccoSync andimages/{id}/downloadIntersight: firmware repository 1 token 2 Bearer calls optional 3 download URL 4 file + checksum
Figure 0. Where ASD sits. ASD never touches your devices: it hands your tooling a file and the checksum to verify it. Controllers such as Catalyst Center and Intersight have their own cisco.com connection and are covered under Companions.

Use 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

  1. Choose targets (Software Suggestion or your standards)
  2. Plan file of PIDs and targets
  3. ASD metadata and download
  4. SHA-512 check
  5. 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

  1. /metadata/pidrelease for the affected PIDs
  2. Collect release, size, SHA-512, minimum DRAM and flash
  3. Add release-note and advisory links
  4. 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

  1. Export image file names and hashes from inventory
  2. /metadata/images, five names per call
  3. Compare SHA-512, flag isDeleted
  4. For advisories, /metadata/pidimage per 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

  1. Download and verify in a connected zone
  2. Carry file and .sha512 across the gap
  3. Re-verify with sha512sum -c inside

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

  1. Metadata per PID
  2. Store isSuggested, lifeCycle, psirtIndicator, advisories, fcsDate
  3. 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 summaryVerdictWhat the v4.0 reference says
ASD is part of the Cisco Support APIs on DevNetCorrectListed first in the Support APIs portfolio.
Token from id.cisco.com/oauth2/default/v1/token, client credentials grantCorrectSame 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 ConsoleCorrectSmart Net Total Care customers and Partner Support Service partners only; the API user also needs the API Developer role.
"Internal Cisco engineering entitlements" grant accessUnsupportedNo 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}WrongPOST /software/v4.0/metadata/pidrelease with a JSON body. The PID goes in the body, not the path.
GET /software/image/v1/imageName/{name}WrongPOST /metadata/pidimage (PID plus 1–5 image names) or POST /metadata/images (names only).
GET /software/download/v1/image/{name}/eulaAccept/trueWrongPOST /download/pidimage with pid, mdfId, imageGuids and metadataTransId. EULA and K9 acceptance are separate /compliance/eula and /compliance/k9 calls.
Response {"downloadUrl", "imageName", "expiryTime"}Wrongdownloads[] 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 callPartlyMD5 and SHA-512 come from the three metadata calls, never from the download call.
ASD returns Gold Star / suggested releasesPartlyASD flags isSuggested per release. Ranked suggestions come from the separate Software Suggestion v2 API.
Catalyst Center POST /dna/intent/api/v1/image/importation/source/ciscoWrongNo 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 fabricPartlyBoth 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.

  1. SNTC or PSS contract
  2. API Developer role (CSAM)
  3. Register app in API Console
  4. Add "Automated Software Distribution"
  5. Contracts on the Cisco.com profile
  6. Software download access (ART)
StepCustomer (SNTC)Partner (PSS)
1. EntitlementSmart 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 roleThe 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 registrationCisco 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 entitlementEach 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 accessContract-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.

Shell · get an access token
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}
ItemDetail
Token endpointPOST https://id.cisco.com/oauth2/default/v1/token, form-encoded grant_type, client_id, client_secret
API hostapix.cisco.com. Older posts and code use api.cisco.com, which was replaced in the same migration.
HeaderAuthorization: Bearer <access_token> and Content-Type: application/json for the POST bodies
Legacy endpointcloudsso.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 linksThe 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.

Shell · first test
pip install requests
export CISCO_CLIENT_ID=…  CISCO_CLIENT_SECRET=…
python asd_client.py C9300-48P 17.9.4

Done 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.

CSV · plan.csv
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
Python 3 · asd_batch.py (same folder as asd_client.py)
# 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.

Shell · crontab entry (02:15 daily)
15 2 * * * cd /opt/asd && ASD_REPO=/srv/images python3 asd_batch.py plan.csv > report-$(date +\%F).json 2>&1 || /opt/asd/alert.sh

Done 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.

Your client id.cisco.com ASD API Download server POST /oauth2/default/v1/token access_token · expires_in 3599 POST /metadata/pidrelease metadataTransId · mdfId · imageGuid · sha512 /compliance/eula · /compliance/k9 (if gated) POST /download/pidimage downloads[].url (60 min) · token · sessionId GET url&access_token=… or POST X-Authentication-Control=token 302 … 302 … 200 image bytes SHA-512 of file = sha512 from step 4
All steps shown
Figure 1. The full download sequence. Steps 3 to 6 must finish within 60 minutes, because the download call needs a live 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.

OperationYou knowBody (fields as in Cisco's samples)Returns a metadataTransId?
POST /software/v4.0/metadata/pidreleaseThe PID and its current releasepid, currentReleaseVersion, outputReleaseVersion (latest, above or a specific release), pageIndex, perPage (max 25)Yes
POST /software/v4.0/metadata/pidimageThe PID and the exact image file namespid, imageNames (array, 1–5), pageIndex, perPage. Unknown names come back in invalidImagesYes
POST /software/v4.0/metadata/imagesOnly file names (for example from a device inventory)imageNames (array, 1–5)No: status, dates, size and checksums only
Request · metadata by PID and release
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"
}
metadata[ ]pid products[ ]mdfId · mdfConceptName softwareTypes[ ]softwareTypeId · softwareTypeName operatingSystems[ ]name releases[ ]version · fcsDate · lifeCycle · isSuggested images[ ]imageGuid · name · size · md5 · sha512encryptionSoftwareIndicator · exception[ ] Top levelmetadataTransIdpaginationinvalidImages[ ] Download callneeds four values:pid · mdfIdimageGuidsmetadataTransId
Figure 2. The metadata response tree. Flatten it to one row per image before deciding; the Python client below does this. The JSON samples use 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.

OperationPurposeBody
GET /compliance/eulaCurrent EULA text, accept and decline values, webForm link, subAppVersionNone
POST /compliance/eulaRecord acceptance or declinestatus (Accepted | Declined), fileNames, declineComments if declined
GET /compliance/k9K9 form fields and values, user details, webForm linkNone
POST /compliance/k9Record the K9 answersstatus, 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.

Request and response · download URLs
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 fieldWhere the image isHow to fetch it
EmptyDefault download serverAppend &access_token=<your API token> to url and request it (the guide's client uses GET).
SetCisco cloud storePOST to url with Content-Type: application/x-www-form-urlencoded and body X-Authentication-Control=<token>. Follow one or more HTTP 302 redirects.
Shell · fetch and verify
# 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.

Shell · generated

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.

Python 3 · asd_client.py (needs 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')
Shell · run it
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 verified

Companions

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".

PathReturns
/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
Shell · suggested releases for two PIDs
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.

Shell · PID to MDF ID (up to 5 PIDs)
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 series

Note 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.

PlatformGet images from cisco.comDistribute and activate
Catalyst Center 2.3.7.x and 3.xPOST /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.

CodeHTTPMeaningWhat to do
Not Authorized403Token invalid, or API key not recognizedGet a new token; check the app has ASD access in the API Console
Account Over Queries Per Second Limit403Too many calls in one secondBack off and serialize; this is ASD's rate-limit signal, not 429
Account Over Rate Limit403Too many calls in the quota periodSlow down; check usage under Keys in the API Console
Account Inactive403Key not approved or disabledContact the Support API team
PROD_REG_NA401Product must be registered and approved for the serviceEmail swc-it-support@cisco.com
PROD_REG_AV401This client ID cannot call the serviceRegister a new client ID; contact swc-it-support@cisco.com
DNAC_REG_REQ401App must be registered for the serviceContact swc-it-support@cisco.com
SW_NO_LONGER_AVL401Software for this product is no longer availablePlatform is retired from the download site
INVALID_OUTPUT_RELEASE401Output release emptySend outputReleaseVersion
PID_INVALID · PID_MISSING400PID invalid or absentCheck spelling and the pid field name
NO_DATA_FOUND_FOR_PID400No software for that PIDTry the base PID; confirm on the download site
CUR_REL_MISSING · OUT_REL_MISSING400Current or output release absentSend both release fields
IMG_NM_MISSING · IMG_NM_INVALID400Image names absent or invalidSend imageNames as an array of exact file names
IMAGE_LIMIT_EXCEEDED400Too many image names or GUIDsFive per call
MDFID_MISSING · MDFID_INVALID400MDF ID absent or invalidUse mdfId from the same metadata response
IMAGE_GUID_MISSING · IMAGE_GUID_INVALID400Image GUID absent or invalidUse imageGuid from the same metadata response
MTRANSID_MISSING · INVALID_MTRANSID400Transaction ID absent or invalidSend metadataTransId from a metadata call
MTRANSID_EXPIRED400Transaction ID older than 60 minutesRe-run the metadata call, then download
INVALID_INPUT400Invalid input or no data foundValidate the body against the Swagger file
Service Not Found596Service missing, often spaces in parametersTrim inputs
SER_UNEXPECT_FAIL500Unexpected service failureRetry later; report with the request data
API Maintenance/Service Unavailable503MaintenanceRetry with backoff
IMG_CONTRACT_REQD200Contract-registered image: metadata only, no URLAdd the covering contract to the Cisco.com profile (Profile Manager)
CONTRACT_NOT_AUTH · CONTRACT_REJECTED200Contracts on the profile do not cover this productAssociate the right contract, or ask the account team or partner
CONTRACT_LOGIN · CONTRACT_IMG_REQ · CONTRACT_REQ_DWLD · CONTRACT_REQD_DWLD · CONTRACT_IMG_DWLD200A valid service contract is requiredSame as above
IAC_ERROR · CONTRACT_ACCESS200No access to download contract-registered softwareRequest Software Download Access in ART
IMG_K9200Strong-encryption image; download not approvedComplete the K9 form; questions to tradeopscpr@cisco.com
K9_IMG_DWLD · K9_FORM_AR · K9_FORM_ACC200K9 form not yet acceptedAccept K9 (see EULA and K9 gates)
EULA_FORM_AR · EULA_FORM_ACC · K9_EULA_FORM_AR200EULA (and possibly K9) not yet acceptedAccept EULA, then K9 if listed
K9_REJECTED200K9 answers under review or rejectedRetry after about 4 hours; tradeopscpr@cisco.com
IP_CHECK_FAIL200Request from a territory not authorized to receive Cisco productsCheck egress location; tradeopscpr@cisco.com
LOGIN_REQD · LOGIN_IMG_DWLD · LOGIN_CONTRACT_REQ200A Cisco.com login (with contract) is requiredThe identity behind the app lacks the profile setup
CPR_ADDRESS_EXCEPTION_MSG200Profile is missing a full addressComplete the address in Profile Manager
C3_USERID_NMAP200User ID not mapped in C3 (a Cisco back-end system)Contact Cisco support
SW_ADV_IMAGE · DEF_ADV_IMAGE200Software or deferral advisory on the imageRead the advisory before using the image
DWLD_WARN · DWLD_WARN1 · DWLD_WARN2200You may not be authorized for the productCheck contract coverage; ent-dl@cisco.com

Operate

Quotas and limits

LimitValueSource
Records per metadata page25ASD reference
PIDs per metadata call1ASD reference
Image names or GUIDs per call1–5ASD reference
metadataTransId and download URL life60 minutesASD reference
Access token life3,600 seconds by defaultSupport APIs authentication page
Calls per second and per dayNot in the ASD referenceThe 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.

WhereTable saysSample uses
/metadata/pidrelease requestPID, OutputReleaseVersion, perpage, target Latestpid, outputReleaseVersion, perPage, latest
Metadata responsesimageName, imageSize, releaseVersion, lifecycle, fieldNoticeUrlname, size, version, lifeCycle, fieldNotice
/metadata/images requestimageNames described as GUIDsImage file names
/compliance/k9 requestbusfunction, confirm = Confirm_Checked, declineComments typed intbusFunction, CONFIRM_CHECKED, text
/compliance/eula requestdeclineComments described as a download session IDFree 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

  1. Confirm entitlement first: SNTC or PSS, API Developer role, ASD visible in the API Console, contracts on the profile, ART software download access.
  2. Use a dedicated automation identity, not a person's Cisco.com login.
  3. Cache the token and renew it about five minutes before expires_in.
  4. Pick the target with Software Suggestion, download with ASD.
  5. Check exception[] on every 200. No URL follows until it is empty.
  6. Finish the download inside 60 minutes of the metadata call; on MTRANSID_EXPIRED start again from metadata.
  7. Never automate K9 or EULA acceptance silently. Have the accountable person accept once.
  8. Verify SHA-512 before an image enters the repository; delete on mismatch.
  9. Keep TLS (Transport Layer Security) verification on and keep tokens out of logs and URLs you store.
  10. Treat 403 as possibly a rate limit: read the message, back off, retry a few times.
  11. Prefer the controller when Catalyst Center or Intersight already manages the devices.
  12. Validate field names against the Swagger YAML for your account before production.

Operate

Figure index

  1. Figure 0Where ASD sitsWhat ASD is
  2. Figure 1End-to-end download sequence (step-through)End-to-end flow
  3. Figure 2Metadata response treeFind images

Operate

Sources

  1. Automated Software Distribution API reference (v4.0): all eight operations, error codes, cloud download
  2. Introduction to Cisco Support APIs: portfolio
  3. Support APIs user onboarding process: SNTC and PSS access
  4. Support APIs application registration: API Console, client credentials
  5. Support APIs authentication: token endpoint and lifetime
  6. Software Suggestion API v2
  7. Product Information API: PID to MDF ID
  8. Cisco Community: legacy cloudsso endpoint for apps before 1 March 2023
  9. Cisco Community: ASD takes the PID in the body (400 otherwise)
  10. Catalyst Center: initiate sync of images from Cisco.com and download the software image
  11. Catalyst Center Software Image Management guide
  12. Ansible swim_workflow_manager module: cisco.com import from 2.3.7.6
  13. Intersight Managed Mode: managing firmware
  14. Cisco API Console: Migrating Applications: token URL and host changes
  15. Cisco API Console: Automated Software Distribution Preview-V3 listing (sign-in required)
  16. Cisco API Console, Register a New App form: per-API rate limits (sign-in required)