Skip to content

Errors

Envelope

Developer API errors carry a single detail key:

{ "detail": "unknown action 'nope'" }

Match on the HTTP status. Treat detail as a human-readable message whose wording may change.

detail is not always a string

Request-body schema failures return 422 with detail as an array of Pydantic error objects rather than a string:

{
  "detail": [
    {
      "type": "missing",
      "loc":  ["body", "payload", "action"],
      "msg":  "Field required"
    }
  ]
}

A client that assumes detail is a string will break on these. Check the status first, or check the type before formatting.

Status codes

HTTP When
400 Business validation. Manifest rejected, plan cap reached, invalid deployment transition, unknown action, rollout percentage out of range, channel name not found.
401 No token, or a token that does not parse or has been revoked.
403 The endpoint requires a personal access token and you used a project token. Deleting a project is the main case.
404 The resource does not exist, or belongs to a project your token cannot see. The two are deliberately indistinguishable.
409 Conflict. Creating a device whose device_id already exists in the project.
422 The request body failed schema validation. See the array form above.
500 Unhandled server error.

Plan limits return 400:

{ "detail": "monthly artifact upload limit reached for current plan; …" }
{ "detail": "Device limit reached for the current plan." }

Device API

The device API uses hardware-safe responses for business outcomes: a device over the plan's device cap gets 200 with "status": "over_limit", not a 4xx. A fleet must never brick itself over a billing state.

You only get 4xx/5xx from /check/ or /status/ for genuine misuse (401/403) or infrastructure failure (5xx).