Errors

Every failure returns the same JSON shape, whatever went wrong — including a mistyped URL. Your client only ever has to parse one thing.

The shape

Error response
{
  "error": {
    "code": "invalid_api_key",
    "message": "The provided API key is not valid.",
    "traceId": "0HN7A2QK9V1M4:00000003"
  }
}

Branch on code, never on message

code is a frozen contract: a new code may be added, but an existing one is never renamed or repurposed. message is human-readable text that may be reworded at any time, and traceId identifies the request in our logs — quote it when contacting support.

Every code

CodeStatusMeaning
missing_api_key401No X-API-Key header was sent.
invalid_api_key401The key is not recognised.
expired_api_key401The key passed its expiry date.
revoked_api_key401The key was revoked in the Nubo portal.
invalid_request400A parameter is missing, malformed or out of range.
plan_limit403A plan or account limit was reached.
project_not_found404No such project in this key's workspace.
session_not_found404No such session in this key's workspace.
rate_limited429Too many requests. See the Retry-After header.
internal_error500Something failed on our side. Retry, and quote the traceId.

A 404 does not distinguish “no such id” from “not in your workspace”. Check the id against GET /v1/projects first.

What to retry

StatusRetry?
400, 401, 403, 404No — the request will fail identically until you change something. Fix the parameters or the key.
429Yes, after the Retry-After header says to.
500Yes, with exponential backoff. If it persists, quote the traceId to support.

A slow first request is not an error

After a quiet period the first call can take up to a minute while the database resumes. That is a slow success, not a failure — set a generous client timeout so you do not abandon a request that was about to succeed.