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

# Errors

> TenantCore uses standard HTTP status codes. All errors return a consistent JSON body.

## Error format

Every error response from the API returns a JSON body in this shape:

```json theme={null}
{
  "detail": {
    "message": "Human-readable description",
    "code": "machine_readable_code"
  }
}
```

Some errors include additional fields. For example, a tenant ceiling error includes your current usage:

```json theme={null}
{
  "detail": {
    "message": "Tenant ceiling reached. Upgrade your plan to provision more tenants.",
    "code": "tenant_limit_reached",
    "plan_name": "API Starter",
    "tenant_limit": 25,
    "connected_tenants_count": 25,
    "remaining_tenants": 0
  }
}
```

## HTTP status codes

| Code  | Meaning                                                               |
| ----- | --------------------------------------------------------------------- |
| `200` | Request succeeded                                                     |
| `400` | Bad request — invalid payload, missing field, or constraint violation |
| `401` | Authentication failed — invalid or missing API key                    |
| `402` | Payment required — no active plan, or tenant ceiling reached          |
| `403` | Forbidden — you do not own the resource you are trying to access      |
| `404` | Not found — tenant, domain, or mailbox does not exist on your account |
| `409` | Conflict — e.g. DNS not yet propagated, or domain already exists      |
| `500` | Internal server error — something went wrong on our side              |

## Error codes

### Authentication errors

| Code                  | Status | Description                                                        |
| --------------------- | ------ | ------------------------------------------------------------------ |
| `invalid_auth_header` | 401    | `Authorization` header is missing or does not start with `Bearer ` |
| `missing_api_key`     | 401    | The Bearer token is present but empty                              |
| `invalid_api_key`     | 401    | The key does not match any active key on record                    |
| `no_api_plan`         | 402    | Your account has no active API plan                                |

### Tenant errors

| Code                   | Status | Description                                             |
| ---------------------- | ------ | ------------------------------------------------------- |
| `tenant_not_found`     | 404    | Tenant does not exist or belongs to a different account |
| `tenant_limit_reached` | 402    | Your plan ceiling would be exceeded by this operation   |

### Domain errors

| Code                   | Status | Description                             |
| ---------------------- | ------ | --------------------------------------- |
| `domain_not_found`     | 404    | Domain is not registered on this tenant |
| `domain_limit_reached` | 400    | Tenant already has 12 domains (maximum) |

### Mailbox errors

| Code                    | Status | Description                                         |
| ----------------------- | ------ | --------------------------------------------------- |
| `mailbox_not_found`     | 404    | Mailbox does not exist on this tenant               |
| `mailbox_limit_reached` | 400    | Domain already has 3 mailboxes (maximum per domain) |
| `invalid_send_limit`    | 400    | `daily_send_limit` must be between 1 and 25         |

## Handling errors in code

```python theme={null}
import requests

response = requests.get(
    "https://api.tenantcore.io/v1/tenants",
    headers={"Authorization": "Bearer tc_live_your_key"}
)

if not response.ok:
    error = response.json().get("detail", {})
    code    = error.get("code")
    message = error.get("message")

    if code == "tenant_limit_reached":
        # Handle ceiling reached
        pass
    elif code == "no_api_plan":
        # Prompt user to purchase a plan
        pass
    else:
        raise Exception(f"API error [{response.status_code}] {code}: {message}")
```

```javascript theme={null}
const res = await fetch("https://api.tenantcore.io/v1/tenants", {
  headers: { Authorization: "Bearer tc_live_your_key" }
});

if (!res.ok) {
  const { detail } = await res.json();
  console.error(`[${detail.code}] ${detail.message}`);
}
```
