Calling the open API: auth, permissions, requests, responses and failures
Operations accept different authentication, so read the operation detail first. An external service calls a customer’s control plane only with an API key the customer issued, and only on operations marked “API key”.
There is no self-service OAuth or client-credentials flow for third parties. The API reference lists every operation’s auth, required permissions, parameters, request and response fields and status codes, all generated from the contracts.
The customer creates and keeps the API key
The customer creates a least-privilege key on their control plane’s “API key” page (/dashboard/account/api-key), with an IP allow-list for your egress and an expiry. The create endpoint POST /v1/account/api-keys takes a session only and needs api_keys.self.manage, an Idempotency-Key and If-Match; it does not accept CdncaKey itself.
The secret appears once, in the issuing receipt; keep it in a controlled secret store, never in a browser front end, a plugin package or a public repository.
Effective permissions are always the key scopes intersected with the owner’s current permissions; when the owner loses a permission the key loses it too.
After rotation the old secret stops working at once.
A first read-only request
This lists security policies and needs security_policies.read. Run it in the customer’s controlled environment:
CDNCA_CONTROL_ORIGIN='https://control.example.com'
# inject CDNCA_API_KEY_ID and CDNCA_API_KEY_SECRET from your secret store
curl --fail-with-body --silent --show-error \
-H "Authorization: CdncaKey ${CDNCA_API_KEY_ID:?}.${CDNCA_API_KEY_SECRET:?}" \
"${CDNCA_CONTROL_ORIGIN}/v1/security-policies?page=1&limit=20"
{"items":[],"total":0,"page":1,"limit":20}
Here page starts at 1 and limit is 1–100; keep fetching until you have total items. Other lists page with an opaque cursor and next_cursor, so do not assume page numbers everywhere; the parameters in each operation’s detail decide.
Writes: idempotency and revisions
Writes with Idempotency-Key: a retry of the same logical operation keeps the key and the body and the server replays the first result; reusing the key with a different body is a conflict.
Writes with If-Match: read the resource for its ETag and send it. Missing gives 428, a changed revision 412; read the latest state and decide again instead of overwriting.
Do not auto-retry every write, and never use a new key to hide an unknown result.
Common failures and next steps
Failures return the error envelope {"error":{"code":"…","message":"…","request_id":"…"}} with an X-Request-ID header. Branch on code; message is not a localisation key. Include request_id when you contact support.
Status
Check first
Next step
400
Parameters and body fields
Fix them per the operation detail; do not retry unchanged
401
Credential format, expiry, rotation
Use a valid credential
403
Key scopes, owner permissions, tenant scope
Ask the customer to adjust; never switch to a more privileged account
404
Resource ID and tenant
Confirm it exists in this tenant
409
Idempotency or state conflict
Read the state back; retries keep the key and body
412 / 428
If-Match revision
Read the latest ETag and decide again
429
Request rate
Wait, then retry with lower concurrency
5xx or network timeout
Whether the request took effect
Read back by ID or list first, then decide whether to retry with the original Idempotency-Key