Interlaken
Requests and responses

Errors

The status codes, the shape of a failure body, and which failures are worth retrying.

The shape

{
  "error": "permission denied",
  "message": "…"
}

error is the part to branch on. It is sometimes a stable machine code, such as invalid_code or challenge_expired, and sometimes the failure stated plainly. message is the human sentence, and is not always present. Some failures add a field of their own, and those are the useful ones:

FieldAppears onUse
required_permission403The exact permission key the route wanted.
attempts_left401 on a second factorHow many tries remain.
retry_after_seconds429How long to wait.

The OAuth endpoints answer in that specification's own shape instead, with error and error_description holding codes such as invalid_client, invalid_grant and invalid_scope.

The codes

CodeMeansDo
400The body or a query parameter did not parse or did not validate.Fix the request. Never retry unchanged.
401No token, or one that is expired, revoked, or not signed by this zone.Get a new token once. If it happens again, the credential is wrong.
403Authenticated, but missing a permission.Read required_permission. Widen the client's scopes.
404No such resource in this tenant.Check the id, and check the zone.
409The resource is in a state that forbids this.Read its status, wait, try again.
429Rate limited.Wait retry_after_seconds.
500The call failed inside the platform.Retry an idempotent call with backoff.
503A dependency the route needs is unavailable.Retry with backoff.

Two that get misread

404 is also the answer for "belongs to someone else." Resources are scoped to the tenant in your token, and a resource in another tenant is indistinguishable from one that does not exist. That is deliberate: it stops the API confirming what exists elsewhere. If a 404 surprises you, check the zone before you check the id.

401 can happen mid-life. Tokens are checked against a revocation list on every request, so rotating a secret, deleting a client or signing out everywhere ends a token before its expires_in does. Treat 401 as "fetch a new token", not as "my clock is wrong".

Retrying

Retry 429, 500, 503 and network failures. Do not retry 400, 403 or 404: nothing about the next attempt will differ.

Exponential backoff with jitter, capped at a minute, and a ceiling on attempts. For 429 specifically, use the retry_after_seconds the body gives you rather than your own schedule.

POST needs care, because it is not idempotent: a request that timed out may still have been applied. Look the resource up by name or tag before creating it again.

On this page