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

# Convenções da API

> O que vale para todos os endpoints: base URL, autenticação, telefone, idempotência, paginação, rate limit e formato de erro.

A API da Arara é REST, com JSON na entrada e na saída. Esta página declara as convenções uma única vez. Para os campos de cada rota, veja a referência de cada endpoint no menu ao lado.

## Base URL

```
https://api.ararahq.com
```

Não há versão no host. Os paths de negócio começam em `/v1`. O prefixo `/api` (`https://api.ararahq.com/api/v1/...`) também é aceito por compatibilidade, mas use a forma sem prefixo.

## Autenticação

Envie a chave de API no header `Authorization`:

```
Authorization: Bearer ara_live_...
```

Crie a chave em [Chaves de API](https://app.ararahq.com/dashboard/apikeys). Permissões, expiração e erros estão em [Autenticação](/api-reference/authentication).

## Telefone

O formato canônico é E.164 com `+`: `+5511999999999`. Use esse formato em corpo, path e query.

No envio de mensagem a API também aceita `5511999999999` e `whatsapp:+5511999999999`. Ela remove o prefixo e o `+` e exige de 7 a 15 dígitos. Fora disso responde `422 INVALID_RECIPIENT`.

`POST /v1/conversations/window-status` não faz essa normalização. Mande só dígitos com DDI, com ou sem `+` (`+5511999999999` ou `5511999999999`). A busca tolera o `+` e o nono dígito de celular brasileiro. Com `whatsapp:`, espaços, parênteses ou hífens o telefone não casa com a conversa e a janela volta como fechada.

## O que a chave de API alcança

| Grupo | Rotas principais | Página |
| - | - | - |
| Mensagens | `POST /v1/messages`, `POST /v1/messages/batch`, `GET /v1/messages/{id}` | [Mensagens](/api-reference/messages) |
| Conversas | `GET /v1/conversations`, `POST /v1/conversations/reply`, `POST /v1/conversations/window-status` | [Mensagens](/api-reference/messages#endpoints) |
| Mídia | `POST /v1/media/upload` | [Mensagens](/api-reference/messages#endpoints) |
| Templates | `/v1/templates`, `/v1/templates/library`, `/v1/templates/sync` | [Templates](/api-reference/templates) |
| Campanhas | `/v1/campaigns`, `/v1/campaigns/estimate`, `/v1/campaigns/{id}/ab-test` | [Campanhas](/api-reference/campaigns) |
| Contatos, opt-out e LGPD | `/v1/contacts`, `/v1/opt-outs`, `/v1/contacts/{phone}/lgpd` | [Contatos](/api-reference/contacts) |
| Identidade da chave | `GET /auth/me`, `GET /auth/me/organizations` | [Identidade](/api-reference/auth) |
| Formulários | `/v1/flows` | [Formulários](/flows) |
| Automações | `/v1/automations` | [Automações pela API](/automacoes-api) |
| Smart links, números, carteira, preços, perfil comercial, recuperação | `/v1/smart-links/whatsapp`, `/v1/organizations/me/numbers`, `/dashboard/wallet/balance`, `/v1/pricing/current`, `/v1/recovery/*` | Referência no menu ao lado |

Gestão de chaves, pagamentos e perfil pessoal são operações do painel e não aceitam chave de API.

O webhook também é configurado só pelo painel, em [Webhooks](https://app.ararahq.com/dashboard/webhooks). URL, lista de entregas, reenvio e teste não funcionam com chave de API. Veja [Webhooks](/webhooks).

## Formato de resposta

Toda resposta com corpo é JSON. Datas em ISO 8601 (UTC).

Exceções:

* `204 No Content` não tem corpo (por exemplo, cancelar campanha).
* `GET /v1/messages/{id}` responde `403` e `404` sem corpo.
* `401` e `403` de autenticação trazem o JSON padrão do servidor, fora do envelope de erro. Veja [Autenticação](/api-reference/authentication#erros-de-autenticação).

### Objeto único

```json theme={null}
{
  "id": "ara_msg_k9Bf2Xq",
  "status": "PENDING",
  "mode": "LIVE",
  "sender": "whatsapp:+5511888888888",
  "receiver": "+5511999999999",
  "body": null,
  "cost": 0.3835,
  "reason": null
}
```

### Listas

O envelope mais comum é `{ data, pagination }`:

```json theme={null}
{
  "data": [{ "id": "a7f3c1e2-...", "name": "pedido_confirmado" }],
  "pagination": { "page": 0, "size": 50, "totalElements": 1, "totalPages": 1 }
}
```

<Warning>
  O envelope de lista muda por rota. Confira antes de ler a resposta:

  | Rota | Envelope |
  | - | - |
  | `GET /v1/templates`, `GET /v1/smart-links/whatsapp` | `{ data, pagination }` |
  | `GET /v1/campaigns` | `{ content, totalPages, totalElements }` |
  | `GET /v1/conversations`, `GET /v1/wallet/transactions` | `{ content, page, size, totalElements, totalPages }` |
  | `GET /v1/contacts` | `{ contacts, total, page, size, totalPages }` |
  | `GET /dashboard/messages` | `{ messages, total, page, size, totalPages }` |
  | `GET /v1/opt-outs` | `{ items, total }` (sem paginação) |
</Warning>

### Erro

```json theme={null}
{
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "Saldo insuficiente.",
    "details": {}
  }
}
```

Trate pelo status HTTP e depois por `error.code`. Falha de autenticação e alguns `404` saem fora desse formato. Códigos e exceções em [Erros](/erros).

## Paginação

| Param | Tipo | Default | Descrição |
| - | - | - | - |
| `page` | integer | `0` | Página, começando em zero. |
| `size` | integer | varia | Itens por página. Default e máximo mudam por rota (ex.: templates 50/200, campanhas 20/100). |

```bash theme={null}
curl "https://api.ararahq.com/v1/templates?page=1&size=50" \
  -H "Authorization: Bearer $ARARA_API_KEY"
```

Os parâmetros são os mesmos em todas as listas paginadas. O nome dos campos da resposta muda por rota, como mostra a tabela em [Listas](#listas). `GET /v1/opt-outs` não tem paginação.

## Idempotência

| Endpoint | `Idempotency-Key` | Comportamento |
| - | - | - |
| `POST /v1/messages` | opcional | Mesma chave, mesmo usuário: devolve a mensagem já criada, sem reenviar nem cobrar. |
| `POST /v1/messages/batch` | opcional | Mesma chave: devolve o lote original. |
| `POST /v1/campaigns` | **obrigatório** | Mesma chave: devolve a campanha já criada. |

Regras:

* A chave tem de 1 a 255 caracteres, sem caracteres de controle. Fora disso: `400 INVALID_IDEMPOTENCY_KEY`.
* A chave não expira.
* Derive a chave de um evento do seu sistema (id do pedido, id da tentativa). Não gere um valor novo a cada chamada, senão a retentativa duplica o envio.
* Em `POST /v1/messages` o corpo não é comparado: reusar a chave com outro destinatário devolve a mensagem antiga, sem erro. Use uma chave por intenção de envio.

```bash theme={null}
curl -X POST https://api.ararahq.com/v1/messages \
  -H "Authorization: Bearer $ARARA_API_KEY" \
  -H "Idempotency-Key: pedido-12345-confirmacao" \
  -H "Content-Type: application/json" \
  -d '{ "receiver": "+5511999999999", "templateName": "pedido_confirmado", "templateVariables": ["João", "12345"] }'
```

## Rate limits

| Tipo | Limite |
| - | - |
| Leitura (`GET`) autenticada | 1.200 por minuto |
| Escrita (`POST`, `PATCH`, `PUT`, `DELETE`) | 3.000 por minuto |

O limite é por usuário dono da chave. Toda resposta traz `X-RateLimit-Remaining`. Ao estourar:

```
HTTP/1.1 429 Too Many Requests
Retry-After: 1
X-RateLimit-Remaining: 0
```

```json theme={null}
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Muitas requisições em pouco tempo. Aguarde e tente novamente.",
    "details": { "retryAfterSeconds": 1 }
  }
}
```

### Quais respostas trazem `Retry-After`

| Resposta | `Retry-After` |
| - | - |
| `429 RATE_LIMIT_EXCEEDED` | Sim, junto com `X-RateLimit-Remaining`. |
| `429 SEND_RATE_LIMITED` | Sim. |
| `429 BATCH_BUSY` | Sim. |
| `429 RECOVERY_RATE_LIMITED` | Sim, 60 segundos. |
| `429` nos hooks de automação | Sim. |
| `429 MARKETING_FREQUENCY_EXCEEDED` | Não. Esperar não resolve: o contato já recebeu marketing demais na janela. |
| `503 SEND_TEMPORARILY_UNAVAILABLE` | Sim. |
| `503` de autenticação (banco indisponível) | Sim, 5 segundos. |

Quando o header vier, espere o tempo indicado e repita a chamada com a mesma `Idempotency-Key`.

## Status HTTP

| Código | Quando |
| - | - |
| `200` | Sucesso com corpo |
| `201` | Recurso criado (template, opt-out) |
| `202` | Aceito para processamento (mensagem, lote) |
| `204` | Sucesso sem corpo (delete, cancelamento) |
| `400` | Payload ou parâmetro inválido |
| `401` | Chave inválida, revogada, expirada ou IP fora da allowlist |
| `402` | Saldo insuficiente |
| `403` | Sem `Authorization`, chave sem permissão para a rota, plano ou conta sem permissão |
| `404` | Recurso não existe |
| `409` | Conflito de estado |
| `422` | Regra de negócio (opt-out, janela fechada, template não enviável) |
| `429` | Rate limit |
| `500` | Erro interno |
| `502` | Provedor externo indisponível |
| `503` | Serviço indisponível. Traz `Retry-After` |

## Status e enums

Enums vêm em maiúsculas (`LIVE`, `MARKETING`, `APPROVED`).

O status da mensagem tem duas grafias:

| Onde | Valores |
| - | - |
| REST (`POST /v1/messages`, `GET /v1/messages/{id}`) | `PENDING`, `SCHEDULED`, `PROCESSING`, `SENT`, `DELIVERED`, `READ`, `FAILED`, `CANCELED` |
| Webhook `message.status_updated` | `queued`, `scheduled`, `processing`, `sent`, `delivered`, `read`, `failed`, `canceled` |

`PENDING` no REST é `queued` no webhook.

## IDs

| Recurso | Formato |
| - | - |
| Mensagem | `ara_msg_` + 7 caracteres base62 (campo `id` do envio) |
| Template, campanha, contato, conversa, smart link | UUID |

Rota que espera UUID e recebe outra coisa responde `400 INVALID_PATH_PARAM`.

## Valores monetários

Custos e saldos (`cost`, `totalCost`, `balance`, `threshold`, `amount`) vêm em **reais, decimal** (`0.3835`). Campos com sufixo `Cents` (`amountCents`, `monthlyPriceCents`) vêm em centavos inteiros.

## CORS

A API só libera CORS para domínios da Arara. Chamada direta do navegador é bloqueada. Chame a API a partir do seu backend.

## Próximos passos

<CardGroup cols={2}>
  <Card title="Autenticação" icon="key" href="/api-reference/authentication">
    Como enviar a chave, permissões e erros.
  </Card>

  <Card title="Erros" icon="circle-exclamation" href="/erros">
    Códigos e como tratar cada um.
  </Card>

  <Card title="Mensagens" icon="paper-plane" href="/api-reference/messages">
    O endpoint mais usado.
  </Card>

  <Card title="Webhooks" icon="bell" href="/webhooks">
    Eventos em tempo real no seu backend.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.