Using the API
Errors
One error shape for every endpoint, and what to do with each status.
A failed request returns a non-2xx status and a JSON body with the same shape everywhere:
{ "success": false, "status": 400, "status_key": "bad_request", "error_key": "invalid_input", "message": "Name is required", "fields": { "name": [{ "path": "name", "error_key": "required", "message": "Name is required" }] }, "vars": {}}| Field | What it holds |
|---|---|
status | The HTTP status, repeated in the body |
error_key | A stable machine code: branch on this, never on message |
message | A sentence for people; it can change |
fields | For invalid input, each failing field's errors, keyed by its path |
vars | Values the error refers to, such as the plan whose limit you reached |
What to do with each statusLink to section
| Status | Retry? | What to do |
|---|---|---|
| 400, 422 | No | Fix the input; fields says which part is wrong |
| 401 | No | Send a valid key: see Authentication |
| 402 | No | The plan's limit is reached, or the feature isn't on the plan; vars names it |
| 403 | No | The key can't reach this project or action |
| 404 | No | The id is wrong, or the resource was deleted |
| 409 | Re-read, then retry | Someone changed the resource first (optimistic_lock_conflict) or it already exists |
| 413, 415 | No | The file is too large, or its type isn't supported |
| 429 | Yes, after a wait | See Rate limits |
| 500, 502, 503, 504 | Yes, with backoff | A failure on our side; retry with exponential backoff |
Each endpoint's page lists the error codes it can return, and the errors every endpoint shares are listed once.
const { data, error, status } = await anyrow.table.get({ params: { project_id: projectId, table_id: tableId },})if (error) { if (status === 404) return null throw new Error(`Anyrow ${status}: ${error.error_key}`)}