Skip to main content
Every response has the same outer shape, so error handling is written once.
A response carries data or error, never both. code is stable and machine-readable; branch on it. message is for people, may be reworded between releases, and for some codes is the underlying parser’s own text; never match on it.

Unknown fields are rejected

The body of POST /v1/frames/insight is decoded strictly. A misspelt field is a 400, not a field quietly ignored:
The same code covers malformed JSON and a body over 1 MiB. This is on your side: a rejected body is a bug you fix in a minute, and an ignored field is a bug you find in three months.

Every code

Two outcomes are not errors and arrive as 200:
  • A frame id that GET /v1/frames/data does not know comes back with no bounding box and an empty datasets list.
  • A dataset licensed per query that the organisation’s credits could not cover is left out of a data answer and named in leftOut with the reason, so the rest of the answer still arrives.

Timeouts

Requests have a 30-second budget. A timed-out request does not reliably produce an error envelope, so handle a non-JSON body on a 5xx. Ordinary errors always carry one.

Handling errors well

Retry only internal, rate_limited after its wait, and transport failures. Every other code is terminal until the request or the credential changes.