Errors
When /v1 refuses a request it answers with an RFC 9457 problem document (Content-Type: application/problem+json) carrying a stable code your client can branch on, and a detail written for the person reading it.
{ "status": 403, "title": "This key does not hold the required scope", "detail": "The key authenticated, but it was not granted the scope this endpoint needs. GET /v1/keys/self lists the scopes it does hold.", "code": "scope_denied"}Branch on code, never on title or detail. Those are prose: they get clearer over time. The code is a promise.
The codes
Section titled “The codes”code |
Status | What it means |
|---|---|---|
missing_credential |
401 | No Round Robin key was presented. A dashboard session token does not count |
unknown |
401 | No key matches the token presented. A revoked key reads this way too, because revocation destroys its secrets and nothing is left to match |
disabled |
401 | The key exists and is switched off. Recoverable |
expired_secret |
401 | The key works, but this secret was replaced and its grace period is over |
scope_denied |
403 | The key authenticated but does not hold the scope this endpoint needs |
resource_denied |
403 | The key holds the scope but was restricted to specific rotations, and this is not one. A restricted key gets this on POST /v1/rotations too, because a new rotation is not one of the rotations it names |
invalid_request |
400 | Something in the request is malformed: an unknown sort field, a page size out of range, a missing from/to, an expand value that does not exist |
precondition_required |
428 | A write arrived without its precondition: an If-Match on a write to something that exists, an Idempotency-Key on a create. Read the resource and send back the ETag it gave you, or send If-Match: * to write unconditionally on purpose; see Conventions |
precondition_failed |
412 | The validator you sent is no longer current, so somebody changed the rotation between your read and your write. Nothing was changed. Read again and retry |
rate_limited |
429 | The key is over its requests-per-minute allowance. Comes with Retry-After and the RateLimit-* headers; see Rate limits |
The 401 bodies also carry a keyId when we could tell which key it was: the only handle you and our support both have, since the secret is not one.
Statuses without a code
Section titled “Statuses without a code”| Status | When |
|---|---|
304 Not Modified |
Your If-None-Match matched. Not an error; see Conventions |
404 Not Found |
No such rotation, user, group or channel in this workspace. An id belonging to another workspace is indistinguishable from one that does not exist, deliberately |
409 Conflict |
The Idempotency-Key on a create made a rotation more than 24 hours ago, which is longer than a retry. Nothing was created; retry with a new key if you meant a second rotation. See Creating things |
500 |
Ours. Nothing about the internals reaches the body; if one is reproducible, tell us |
Two refusals worth telling apart
Section titled “Two refusals worth telling apart”403 is not 404. A rotation outside your key’s selector answers 403 resource_denied, not “no such rotation”, so the refusal points you at the key rather than at the id. GET /v1/keys/self shows you the selector.
412 is not a failure. It means the rotation moved between your read and your write, which happens on its own: the schedule advances, somebody rotates from Slack. Nothing was changed, and the fix is to read again and write again. A client that retries with the same stale validator gets 412 forever.
401 unknown is not 401 missing_credential. The first means we do not recognise the token you sent; the second means you sent no Round Robin token at all, most often because a dashboard session token was used instead.
Bad input is refused, not corrected
Section titled “Bad input is refused, not corrected”An unknown sort field or an unrecognised ?expand= value comes back 400 rather than being ignored, so a parameter that did not take is never mistaken for one that matched nothing.
Next steps
Section titled “Next steps”- Authenticating with an API key: the
401codes in context - Scopes and access: what produces a
403 - Conventions: paging and sorting, where most
400s come from - Rate limits: the allowance behind
rate_limited, and the headers that stop you reaching it
