> ## Documentation Index
> Fetch the complete documentation index at: https://docs.guardhousehq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> How error responses are structured and how to interpret status codes.

Every JSON endpoint returns the same envelope on both success and failure. On success,
`status.code` is `0`, `errors` is empty, and `data` carries the payload. On failure,
the HTTP status reflects the broad failure category and the envelope's `status` /
`errors` fields carry detail.

## Envelope shape

```json theme={null}
{
  "status": {
    "code": 100,
    "errorMessage": "Customer 1099 is outside the scope of this API key."
  },
  "data": null,
  "count": null,
  "message": "Customer 1099 is outside the scope of this API key.",
  "errors": [
    {
      "code": 100,
      "message": "Customer 1099 is outside the scope of this API key."
    }
  ]
}
```

## HTTP status codes

| Status | Meaning                                                                                                         |
| ------ | --------------------------------------------------------------------------------------------------------------- |
| `200`  | Success. Inspect `status.code` for service-level result detail.                                                 |
| `201`  | Resource created (used by some webhook subscribe operations).                                                   |
| `400`  | Validation failure. The `errors` array names the offending fields.                                              |
| `401`  | Missing, expired, or invalid bearer token. Re-authenticate.                                                     |
| `403`  | Authenticated, but the resource is outside your API key's `KeyType` or `CompanyId`/`CustomerId`/`SiteId` scope. |
| `404`  | Resource does not exist or has been archived.                                                                   |
| `429`  | Rate limit exceeded (60 requests per minute on external endpoints).                                             |
| `500`  | Unhandled server error. Retry with backoff; if persistent, contact support with the trace ID.                   |

## Status codes inside the envelope

`status.code` is a numeric service-level code that gives more nuance than the HTTP status.
The most common values are:

| `status.code` | Meaning                                                                             |
| ------------- | ----------------------------------------------------------------------------------- |
| `0`           | Success.                                                                            |
| `100`         | Generic application error. Inspect `status.errorMessage` and `errors[]` for detail. |
| `401`         | Authentication required or rejected (mirrors HTTP `401`).                           |
| `403`         | Authorization failed (mirrors HTTP `403`).                                          |
| `404`         | Resource not found (mirrors HTTP `404`).                                            |

<Note>
  The full `ServiceResultType` catalog evolves over time. For unrecognised codes, fall back to
  the HTTP status and the `errors[].message` text — both are stable contracts.
</Note>

## Retry strategy

* **`401`** — refresh the bearer token and retry once. Do not retry blindly; if the
  refresh also fails, the API key has likely been revoked.
* **`403`** — do not retry. Fix the request scope.
* **`429`** — back off. Honour the next minute boundary; the limit is a fixed window.
* **`5xx`** — retry with exponential backoff (e.g., 1s, 2s, 4s, 8s) up to a small cap.
  Treat the request as non-idempotent if you cannot guarantee otherwise.
