Skip to Content
APIError codes

Error codes

Every error body carries a code. Codes are stable within a version, so branch on them rather than on the message text. New codes may be added within v1, so treat an unrecognised code as a generic failure of its HTTP status class rather than crashing.

Authentication

invalid_token

401. The Authorization header is missing, malformed, or the key does not exist.

Check the header is exactly Authorization: Bearer asky_sk_.... The most common cause is a stray newline, quote, or trailing space picked up when the key was copied into an environment variable. Verify with GET /v1/me.

token_expired

401. The key passed its expiration date.

Roll the key to get a working replacement with the same name, scopes, and brand access. If you received expiry reminder emails and no one acted, check they are reaching a monitored address.

token_revoked

401. The key was revoked, or it was replaced by a roll and its grace window has closed.

If a roll is in progress, deploy the new value. If someone revoked it deliberately, ask before minting a replacement: it may have been revoked because it leaked.

Authorization

insufficient_scope

403. The key is valid but does not carry the scope this endpoint requires.

The message names the scope needed. GET /v1/me lists what the key has. Scopes cannot be added to an existing key, so create a new one with the access you need. See API keys.

plan_required

403. API access is not enabled for this workspace.

Contact us to enable it. This is not something you can change in Settings.

Requests

invalid_request

400. The request is malformed. The message names the problem.

Common causes: an unknown query parameter, usually a typo, since unknown parameters are rejected rather than ignored; a badly formatted date, which must be YYYY-MM-DD; a limit above 100; a date range wider than the endpoint allows; or a malformed id.

invalid_cursor

400. The cursor value is not valid for this request.

Cursors are opaque and short-lived. This usually means the cursor was stored and reused later, was modified, was issued for a different query, or came from a different key. Restart the walk from the first page.

not_found

404. The resource does not exist, or your key cannot reach it.

Both cases return the same response on purpose. Check the id came from a listing endpoint under the same key, and check GET /v1/me for the key’s workspace and brand access. A key restricted to specific brands returns this for every other brand.

method_not_allowed

405. v1 is read-only. Use GET.

Limits

rate_limited

429. Too many requests for this key in the current window.

Wait for Retry-After, then retry with exponential backoff and jitter. If you hit this routinely, raise limit to fetch more per request, filter server-side, or reduce polling frequency.

Server

internal_error

500. Something failed on our side. The request was not your fault.

Retry with backoff. If it persists, contact us with the request_id, which lets us find the exact failure in our logs.

service_unavailable

503. Temporarily unavailable, usually brief and usually during a deployment.

Retry after Retry-After. A scheduled sync should treat this as transient rather than alerting a person on the first occurrence.

Quick reference

CodeStatusRetry?
invalid_token401No
token_expired401No
token_revoked401No
insufficient_scope403No
plan_required403No
invalid_request400No
invalid_cursor400No, restart the walk
not_found404No
method_not_allowed405No
rate_limited429Yes, after Retry-After
internal_error500Yes, with backoff
service_unavailable503Yes, after Retry-After
Last updated on