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

# Errors

> Every Xobito API error uses a consistent JSON envelope.

Every error returned by the Xobito API follows a consistent shape. Use the HTTP status for classification and the `message` (and optional `errors`) for detail.

## Error envelope

```json theme={null}
{
  "status": "error",
  "message": "Human-readable description",
  "errors": { "field_name": ["error 1", "error 2"] }
}
```

| Field     | Always present            | Meaning                                                |
| --------- | ------------------------- | ------------------------------------------------------ |
| `status`  | Yes (except 429)          | Always `"error"` on failures.                          |
| `message` | Yes                       | A short human-readable description.                    |
| `errors`  | Only on validation errors | Field-by-field validation messages (object or string). |

<Note>
  `429` rate-limit responses use a different shape — see [Rate Limits](/developers/rate-limits).
</Note>

## HTTP statuses

### 400 Bad Request

Returned when the subdomain path segment is invalid.

```json theme={null}
{
  "status": "error",
  "message": "Validation failed",
  "errors": "Invalid tenant subdomain"
}
```

### 401 Unauthorized

The token is missing or not recognised.

**Missing header:**

```json theme={null}
{
  "status": "error",
  "message": "API token is required"
}
```

**Invalid / revoked / expired token:**

```json theme={null}
{
  "status": "error",
  "message": "Invalid API token"
}
```

### 403 Forbidden

**Missing ability (scope):**

```json theme={null}
{
  "status": "error",
  "message": "Token does not have the required ability: contacts.create"
}
```

The ability name in the message matches exactly the scope the endpoint requires.

**Plan limit exceeded** (e.g. max contacts for the workspace plan):

```json theme={null}
{
  "status": "error",
  "message": "Contact limit exceeded for your current plan. Upgrade to add more contacts."
}
```

### 404 Not Found

The resource does not exist (or does not belong to your workspace).

```json theme={null}
{
  "status": "error",
  "message": "Contact not found"
}
```

The resource name in the message varies by endpoint (`Contact not found`, `Status not found`, `Template not found`, etc.).

### 422 Unprocessable Entity

Validation failed. The `errors` object maps field names to an array of human-readable messages.

```json theme={null}
{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "phone": ["The phone field is required."],
    "email": ["The email has already been taken."]
  }
}
```

### 429 Too Many Requests

Rate limit exceeded. See [Rate Limits](/developers/rate-limits).

```json theme={null}
{
  "message": "Too many requests",
  "retry_after": 45
}
```

### 500 Internal Server Error

Something broke on Xobito's side. The message describes the failed action.

```json theme={null}
{
  "status": "error",
  "message": "Failed to create contact"
}
```

Retry after a short delay. If the error persists, contact support.

## Handling errors

<CodeGroup>
  ```javascript JavaScript theme={null}
  const res = await fetch(url, { headers });
  if (!res.ok) {
    const body = await res.json();
    if (res.status === 422) {
      console.error("Validation failed:", body.errors);
    } else if (res.status === 429) {
      await new Promise((r) => setTimeout(r, (body.retry_after || 1) * 1000));
    } else {
      throw new Error(`${res.status}: ${body.message}`);
    }
  }
  ```

  ```python Python theme={null}
  r = requests.get(url, headers=headers)
  if not r.ok:
      body = r.json()
      if r.status_code == 422:
          print("Validation failed:", body["errors"])
      elif r.status_code == 429:
          time.sleep(body.get("retry_after", 1))
      else:
          raise RuntimeError(f"{r.status_code}: {body['message']}")
  ```
</CodeGroup>

## Common mistakes

<AccordionGroup>
  <Accordion title="401 'API token is required'">
    The `Authorization` header was missing. It must be exactly `Authorization: Bearer <your_token>` (64-character hex string, no prefix).
  </Accordion>

  <Accordion title="403 with ability name">
    Your token is valid but lacks the specific ability. Regenerate a new token in **Settings → API Management** with the ability the endpoint requires.
  </Accordion>

  <Accordion title="400 'Invalid tenant subdomain'">
    The `{subdomain}` in the URL path does not match any workspace. Check the path: `https://dash.xobito.com/api/v1/{subdomain}/...`.
  </Accordion>

  <Accordion title="422 on send-template">
    Either the template does not exist, does not belong to your workspace, or is not yet APPROVED by Meta. Only APPROVED templates can be sent.
  </Accordion>
</AccordionGroup>
