Mental model
Cisco objective 2.3 says “Describe the constraints when consuming APIs”. No API gives you unlimited calls, unlimited result sizes, and perfect uptime. The four constraints you will hit, in order of how often:
- Rate limits — too many calls, too fast.
- Pagination — too many results in one response.
- Payload size — request or response too big.
- Auth — token expired or lost; permissions insufficient.
Knowing each pattern turns a frustrating 429 or truncated list into a quick fix.
Rate limits
How you see it
Server responds with 429 Too Many Requests and often a Retry-After header (seconds to wait).
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{"error":"rate limit exceeded, retry in 30 seconds"}
Common Cisco rate limits
- Meraki Dashboard API: 10 requests per second per organisation. Returns 429 with Retry-After.
- Webex API: rate-dependent per method; returns 429 with Retry-After.
- Catalyst Center: per-token rate limiting; see docs for the specific endpoint.
How to handle in Python
import time
import requests
def polite_get(url, headers):
for attempt in range(5):
r = requests.get(url, headers=headers)
if r.status_code != 429:
r.raise_for_status()
return r
wait = int(r.headers.get("Retry-After", "1"))
time.sleep(wait)
raise RuntimeError("rate limited for too long")
For long batch jobs: pre-sleep a few milliseconds between calls so you never hit the limit.
Pagination
Big result sets (thousands of clients, every device alert from the last month) are chunked.
Classic (limit + offset)
GET /clients?limit=100&offset=0 → first 100
GET /clients?limit=100&offset=100 → next 100
GET /clients?limit=100&offset=200 → next 100
...
Stop when the response has fewer than limit items.
Cursor-based (newer)
Response has a next field (either a cursor string or a full URL):
GET /clients?limit=100
→ {"items": [...], "next": "/clients?cursor=abc123"}
GET /clients?cursor=abc123
→ {"items": [...], "next": "/clients?cursor=def456"}
GET /clients?cursor=def456
→ {"items": [...], "next": null}
Loop until next is null / missing.
Python helper
def all_pages(session, url, headers):
while url:
r = session.get(url, headers=headers)
r.raise_for_status()
body = r.json()
yield from body.get("items", [])
url = body.get("next") # or None → loop ends
Link header pagination (GitHub-style)
Some APIs put the next URL in a Link response header:
Link: <https://api.example.com/x?page=2>; rel="next"
Parse r.links["next"]["url"] in requests (it does the parsing for you).
Payload size
- Request bodies: usually 1-10 MB max. Hitting it returns 413 Payload Too Large.
- Response bodies: APIs usually paginate instead of returning a 100 MB JSON. If you got what looks like a complete list in one call, check that it is not truncated.
- Base64-encoded files balloon payloads; prefer multi-part upload where available.
Mitigation: paginate (above); split batch work into smaller chunks (e.g., register 10 devices at a time, not 1000).
Auth constraints
Token expiry
OAuth2 tokens usually live 1 hour. Scripts that run longer need to re-authenticate when they get a 401 mid-run.
if r.status_code == 401:
token = refresh_token()
r = requests.get(url, headers={"Authorization": f"Bearer {token}"})
Scope / permissions
A token issued to a read-only service account cannot POST. Returns 403.
IP allow-lists
Some APIs restrict calls to specific source IP ranges. Not visible in the response (usually a 403 or 404 from an edge proxy before reaching the API).
Troubleshooting ladder
| What you see | Likely cause | First fix |
|---|---|---|
| 429 | Rate limit | Sleep per Retry-After and retry |
| Truncated list | Pagination missed | Follow next / increase offset |
| 413 | Request body too big | Split the batch, upload the file via chunks |
| 401 after N minutes | Token expired | Re-authenticate |
| 403 on a specific endpoint | Scope / permission | Request wider scope from the admin |
See troubleshoot REST APIs for the full method.
FAQ
Is there a “polite calls per second” number for Cisco APIs? Meraki: 10 per second per org. Catalyst Center: see your version’s docs; often 50 calls/min per token. Treat these as hard caps and leave a buffer.
Why do some APIs use limit/offset and others use cursors? Cursors are more efficient on huge datasets (database does not have to count skipped rows). Limit/offset is simpler to document. Modern APIs lean cursor; older ones lean limit/offset.
What is a 503 vs a 429? 503 Service Unavailable = the server is overloaded or down. 429 = you specifically are over your quota. Both have Retry-After guidance.
Can I avoid rate limits by using multiple API keys? Technically yes; practically that violates most providers’ terms of service. Use the batch endpoints the vendor provides instead.
