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

# Erros e rate limits

> Códigos canônicos, buckets send/read e headers 429.

# Erros e rate limits

## Envelope de erro

```json theme={null}
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded"
  }
}
```

Sempre trate `error.code` de forma estável — a mensagem pode evoluir.

## Rate limits

Janela deslizante de **60 segundos**, compartilhada entre workers.

| Bucket | Limite inicial | Uso                                              |
| ------ | -------------- | ------------------------------------------------ |
| `send` | 60/min         | Envio **novo** (`POST /messages`)                |
| `read` | 600/min        | `GET /ping`, `GET /messages/{id}`, webhooks CRUD |

Dedup (`200` + `deduplicated: true`) e `409 idempotency_key_reused` **não** consomem o bucket `send`.

Quando estourar → **`429`** com:

| Header                  | Significado                  |
| ----------------------- | ---------------------------- |
| `Retry-After`           | Segundos para tentar de novo |
| `X-RateLimit-Limit`     | Limite do bucket             |
| `X-RateLimit-Remaining` | Restante                     |
| `X-RateLimit-Reset`     | Unix timestamp do reset      |

Body: `error.code = rate_limited`.

## Códigos comuns

### Auth (`401`)

| code               | Quando                       |
| ------------------ | ---------------------------- |
| `api_key_required` | Header ausente               |
| `invalid_api_key`  | Key inexistente / malformada |
| `api_key_revoked`  | Revogada                     |
| `api_key_expired`  | Expirada                     |

### Envio

| HTTP      | code                                  | Quando                         |
| --------- | ------------------------------------- | ------------------------------ |
| 400       | `client_message_id_required`          | Campo ausente/vazio            |
| 400       | `invalid_whatsapp_number`             | Número inválido na Meta        |
| 400       | `media_url_forbidden`                 | URL privada / SSRF             |
| 400 / 422 | `outside_customer_window`             | Texto/mídia fora da janela 24h |
| 403       | `channel_forbidden` / `missing_scope` | Canal ou scope                 |
| 409       | `idempotency_key_reused`              | Mesmo id, body diferente       |
| 409       | `identity_conflict`                   | Handle já em outro contato     |
| 422       | `template_not_approved`               | Modelo não aprovado            |
| 429       | `rate_limited`                        | Bucket send/read               |

### Leitura

| HTTP | code                | Quando                          |
| ---- | ------------------- | ------------------------------- |
| 403  | `missing_scope`     | Sem `messages:read`             |
| 404  | `message_not_found` | Fora da org ou mensagem interna |

## Boas práticas

1. Gere `client_message_id` estável no seu sistema (ex. `crm-order-123-msg-1`).
2. Em retry de rede, reenvie o **mesmo** body.
3. Em `429`, respeite `Retry-After` com backoff.
4. Prefira webhooks a polling agressivo de status.
