> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.cail.health/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.cail.health/_mcp/server.

# Errors

When a request fails, the API returns a non-2xx HTTP status and a JSON body. Most failures share a common shape; a few return a reduced shape. The [Error envelope](/reference/error-envelope) reference describes every variation. This page covers how to handle errors in a client.

## The standard shape

```json
{
  "statusCode": 401,
  "message": "Invalid or expired token",
  "error": "Unauthorized",
  "meta": {
    "requestId": "4a3b2c1d-5e6f-4890-9abc-def0fedcba98",
    "timestamp": "2026-05-15T10:30:45.000Z"
  }
}
```

| Field        | Type                       | Notes                                                           |
| ------------ | -------------------------- | --------------------------------------------------------------- |
| `statusCode` | integer                    | The HTTP status, mirrored into the body.                        |
| `message`    | string or array of strings | A human-readable description. An array for validation failures. |
| `error`      | string                     | A short label for the status class. Not always present.         |
| `code`       | string                     | A machine-readable label. Present on some failures only.        |
| `meta`       | object                     | Carries `requestId` and `timestamp`. Not always present.        |

## Branch on the HTTP status code

Field availability is not uniform: `error`, `code`, and `meta` may be absent, and some errors omit `statusCode` from the body entirely. The one signal always available is the **HTTP status code of the response itself**. Branch on that first. Use `code` when it is present for a more precise decision, but never require it.

## Handle `message` as a string or an array

`message` is always present, but its type varies. For a validation failure it is an array of individual messages:

```json
{
  "statusCode": 400,
  "message": [
    "latitude must not be less than -90",
    "latitude must not be greater than 90"
  ],
  "error": "Bad Request",
  "meta": {
    "requestId": "5e6f7a8b-9c0d-4123-a4b5-c6d7e8f9a0b1",
    "timestamp": "2026-05-15T10:30:45.000Z"
  }
}
```

Normalise it in your client, for example by joining an array into a single string before display.

## Handling by status

| Status | Meaning                                           | What to do                                                                                |
| ------ | ------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| 400    | The request was malformed or failed validation.   | Fix the request from `message`. Do not retry it unchanged.                                |
| 401    | The token is missing, invalid, or expired.        | Obtain a fresh token and retry once. See [Authentication](/api-reference/authentication). |
| 403    | The token is valid but not permitted this action. | Do not retry. The same token will keep failing.                                           |
| 404    | The resource does not exist or is not visible.    | Do not retry. Check the identifier.                                                       |
| 409    | The request conflicts with current state.         | Refetch the current state, then retry.                                                    |
| 429    | Too many requests in a short window.              | Back off, then retry.                                                                     |
| 5xx    | A server-side fault.                              | Retry with backoff rather than immediately.                                               |

## Support traceability

When the response includes `meta.requestId`, log it. Including it in a support request lets the team locate the exact request and its server-side context.