# Errors

> The error shape and the status codes you should handle.

CorrectInbox uses conventional HTTP status codes and returns a consistent JSON body on every error.

## Error shape

```json
{
  "object": "error",
  "type": "account_restricted",
  "status": 403,
  "detail": "The provider has restricted this action for this account.",
  "request_id": "req_a1b2c3"
}
```

Always log `request_id` — quote it when contacting support and it points straight at the failed request.

## Status codes

| Status | `type` | Meaning |
| --- | --- | --- |
| `400` | `invalid_request` | A field is missing or malformed. `detail` says which. |
| `401` | `invalid_api_key` | The API key is missing, malformed or revoked. |
| `403` | `insufficient_scope` | The key may not perform this action. |
| `403` | `account_restricted` | The provider restricted this action for the account. |
| `404` | `not_found` | No such object, or it isn't in your workspace. |
| `409` | `already_exists` | The resource already exists (for example, a duplicate account). |
| `422` | `unprocessable` | The request was understood but can't be completed as asked. |
| `429` | `rate_limited` | Too many requests — see [Rate limits](/rate-limits). |
| `5xx` | `server_error` | Something went wrong on our side. Safe to retry with backoff. |

## Handling restrictions

`account_restricted` is an expected outcome, not a bug in your integration — the provider decides it per account. Surface it to your user and either retry later, let the account mature, or run the action on a different account. See [Connection status](/connection-status).

## Empty is not an error

Some reads (notably [search](/search)) return `200` with an empty list when an account has limited access on the provider. Check the result count — and the `limited` flag where present — rather than treating empty as a failure.
