Para IA

Doc para IA (LLM)

Toda a documentação em um único texto Markdown. Copie e cole no seu assistente de IA (ou baixe o arquivo) para ele escrever a integração por você.

Abrir como texto puro31 KB

Nunca cole a sua chave de API real em conversas com IA. Use o valor de exemplo e coloque a chave em uma variável de ambiente.

# ZapyChat — API pública

Base URL: `https://api.zapychat.com.br/api/v1`
Autenticação: cabeçalho `Authorization: Bearer pk_...` (chave criada em Configurações › API Keys).
Permissões da chave: `read` (rotas GET) e `write` (rotas que criam/alteram). Rotas marcadas como "aberta" não precisam de chave.
Toda resposta de sucesso vem como `{ "data": <conteúdo>, "meta": { "timestamp": "..." } }`; os exemplos abaixo mostram o conteúdo de `data`.
Erros: `{ "statusCode", "message", "error", "timestamp", "path" }`. Códigos: 400 inválido, 401 chave inválida, 402 assinatura vencida, 403 sem permissão, 404 não encontrado, 409 conflito, 429 limite de chamadas.
Listas: `page` (padrão 1) e `limit` (1–100, padrão 25); resposta `{ items, total, page, limit }`. Histórico de mensagens usa cursor `before`/`nextBefore`.
Limites: 300 chamadas/min por chave (painel 120/min), 60 mensagens/min, texto até 4096 caracteres.

## Guia: Visão geral

Integre o seu sistema ao ZapyChat com uma API REST simples: consulte conversas, contatos e avaliações, envie mensagens e receba eventos em tempo real.

### O que você pode fazer

- Conversas: listar, ler o histórico, responder e encerrar.
- Mensagens: enviar texto para qualquer telefone por um canal de WhatsApp.
- Contatos e tags: criar, buscar, editar e organizar a base de clientes.
- Tarefas: criar e concluir tarefas da equipe.
- Avaliações: ler as notas do atendimento e dos atendentes.
- Painel: puxar os indicadores do dashboard para os seus relatórios.
- Webhooks: receber um aviso no seu servidor a cada evento importante.

### Como funciona

Todas as chamadas são HTTPS com JSON. Você cria uma chave de API no painel, envia a chave no cabeçalho Authorization e recebe as respostas dentro de um objeto { data, meta }.

Já tem uma chave? Vá direto ao Início rápido e faça a primeira chamada em um minuto.

## Guia: Início rápido

Da chave de API à primeira resposta em três passos.

### 1. Crie uma chave de API

No painel, abra Configurações › API Keys e crie uma chave. Marque a permissão de escrita só se for enviar mensagens ou alterar dados. Copie a chave (começa com pk_): ela aparece uma única vez.

### 2. Teste a chave

```bash
curl "$BASE_URL/public/me" \
  -H "Authorization: Bearer pk_sua_chave"
```

### 3. Liste as conversas abertas

```bash
curl "$BASE_URL/public/conversations?status=OPEN&limit=10" \
  -H "Authorization: Bearer pk_sua_chave"
```

BASE_URL é o endereço da sua API terminando em /api/v1. Os exemplos da Referência já mostram o endereço certo.

## Guia: Conceitos

Os nomes que aparecem em todas as rotas.

| Termo | O que é |
|---|---|
| Empresa | A conta do cliente no ZapyChat. A chave de API pertence a uma empresa e só acessa os dados dela. |
| Canal | Uma conexão de atendimento: um número de WhatsApp, uma conta de Instagram ou um e-mail. |
| Contato | Uma pessoa que fala com a empresa. É identificado pelo telefone ou e-mail. |
| Conversa | A troca de mensagens com um contato em um canal. Tem um status: PENDING, BOT, OPEN, WAITING ou CLOSED. |
| Mensagem | Cada texto, imagem ou arquivo da conversa. direction diz se veio do cliente (INBOUND) ou da empresa (OUTBOUND). |
| Tag | Etiqueta colorida para organizar contatos e conversas. |
| Avaliação | A nota de 1 a 5 estrelas que o cliente dá ao atendimento e ao atendente. |

## Guia: Autenticação

Toda chamada usa uma chave de API no cabeçalho Authorization.

```http
Authorization: Bearer pk_sua_chave
Content-Type: application/json
```

### Permissões da chave

| Permissão | Libera |
|---|---|
| read | Todas as rotas de consulta (GET). Toda chave tem. |
| write | Rotas que criam ou alteram dados (POST, PATCH, DELETE). Só chaves criadas com esta permissão. |

### O que a chave enxerga

A chave age como o usuário que a criou. Se esse usuário é um atendente com acesso restrito a certos canais ou só às próprias conversas, a API respeita as mesmas regras.

Trate a chave como uma senha: não coloque em código de navegador nem em repositório público. Se vazar, revogue em Configurações › API Keys e crie outra.

## Guia: Respostas e erros

O formato das respostas e o significado de cada código.

### Resposta de sucesso

```json
{
  "data": { "id": "cmf3k9x1a0001", "status": "OPEN" },
  "meta": { "timestamp": "2026-10-05T14:32:10.000Z" }
}
```

### Resposta de erro

```json
{
  "statusCode": 404,
  "message": "Conversa não encontrada",
  "error": "NotFoundException",
  "timestamp": "2026-10-05T14:32:10.000Z",
  "path": "/api/v1/public/conversations/abc"
}
```

Em erros de validação, message pode ser uma lista de textos.

| Código | Significado |
|---|---|
| 200 / 201 | Deu certo. |
| 400 | Algum campo está ausente ou inválido. A mensagem diz qual. |
| 401 | Chave ausente, errada, vencida ou revogada. |
| 402 | Assinatura da empresa vencida: só leitura até renovar. |
| 403 | A chave não tem a permissão necessária (por exemplo, write). |
| 404 | Não existe, ou a chave não tem acesso a esse item. |
| 409 | Conflito: contato pediu para não receber mensagens, tag já existe, janela de 24 h fechada… |
| 429 | Limite de chamadas excedido. Aguarde e tente de novo. |
| 5xx | Falha do nosso lado. Tente novamente em alguns instantes. |

## Guia: Paginação

Listas grandes vêm em páginas.

As listas aceitam page (começa em 1) e limit (de 1 a 100, padrão 25) e respondem com os itens e o total.

```json
{
  "items": [ ... ],
  "total": 134,
  "page": 2,
  "limit": 25
}
```

O histórico de mensagens usa um cursor: repita a chamada com before igual ao nextBefore recebido até ele vir null.

Para manter outro sistema sincronizado, use o filtro updatedSince nas conversas e guarde a data da última sincronização.

## Guia: Limites e boas práticas

Para a API continuar rápida para todo mundo.

| Limite | Valor |
|---|---|
| Chamadas por chave | 300 por minuto |
| Painel (dashboard) | 120 por minuto |
| Mensagens enviadas por chave | 60 por minuto |
| Tamanho do texto da mensagem | 4096 caracteres |
| Período das consultas por data | até 1 ano |

- Ao receber 429, espere alguns segundos e tente de novo, aumentando a espera a cada falha.
- Prefira webhooks a ficar consultando a API de tempos em tempos.
- Guarde os ids que a API devolve em vez de buscar de novo.

## Guia: Webhooks de saída

O ZapyChat chama o seu servidor quando algo acontece, sem você precisar perguntar.

Cadastre a URL em Configurações › Webhooks e escolha os eventos. Guarde o segredo mostrado na criação: é com ele que você confere que a chamada veio mesmo do ZapyChat.

### Eventos

| Evento | Quando acontece |
|---|---|
| message.received | Chegou uma mensagem de um cliente. |
| conversation.status_changed | O status de uma conversa mudou (aberta, encerrada…). |
| conversation.assigned | Uma conversa foi atribuída a um atendente. |
| tag.added | Uma tag foi aplicada a uma conversa ou contato. |
| tag.removed | Uma tag foi removida de uma conversa ou contato. |

### Corpo da chamada

```json
{
  "id": "evt_123",
  "event": "message.received",
  "organizationId": "cmf0org001",
  "createdAt": "2026-10-05T14:32:10.000Z",
  "data": { ... }
}
```

### Conferindo a assinatura

Cada chamada traz os cabeçalhos X-ChatPRO-Event, X-ChatPRO-Timestamp e X-ChatPRO-Signature. A assinatura é sha256= seguido do HMAC-SHA256, com o seu segredo, do texto "{timestamp}.{corpo}".

```javascript
import crypto from 'node:crypto';

function assinaturaValida(segredo, timestamp, corpoBruto, assinatura) {
  const esperada =
    'sha256=' + crypto.createHmac('sha256', segredo).update(`${timestamp}.${corpoBruto}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(esperada), Buffer.from(assinatura));
}
```

Responda com um código 2xx em poucos segundos. Um endereço que falha muitas vezes seguidas é desativado automaticamente.

## Guia: Avaliações de atendimento

Como o cliente avalia e como você lê as notas.

Ao encerrar uma conversa, o cliente recebe um pedido de avaliação (se o envio automático estiver ligado em Configurações › Avaliações). Ele dá de 1 a 5 estrelas ao atendimento e ao atendente e pode comentar.

| Estrelas | Significado |
|---|---|
| 1 | Ruim |
| 2 | Regular |
| 3 | Bom |
| 4 | Muito bom |
| 5 | Excelente |

Use GET /public/ratings para a lista e GET /public/ratings/summary para médias e ranking. Para encerrar uma conversa e disparar a pesquisa pela API, use POST /public/conversations/{id}/close.

## Guia: Usando com assistentes de IA

Dê a documentação inteira a um assistente para ele escrever a integração por você.

A aba “Doc para IA” gera um texto único, em Markdown, com toda a referência. Copie e cole no seu assistente (ou baixe o arquivo) e peça, por exemplo: “crie uma função que lista as conversas abertas e responde às que estão sem resposta”.

Nunca cole a sua chave de API real em conversas com IA. Use um valor de exemplo e coloque a chave em uma variável de ambiente.

## Referência: Identidade

### GET /public/me — Quem sou eu

Identifica a chave de API: o usuário dono, a empresa e as permissões. Use para testar se a chave está funcionando.

Permissão: read

Exemplo de resposta (`data`):
```json
{
  "user": {
    "id": "cmf1usr456",
    "name": "João Lima",
    "email": "joao@empresa.com"
  },
  "organization": {
    "id": "cmf0org001",
    "name": "Minha Empresa",
    "slug": "minha-empresa",
    "userRole": "ADMIN"
  },
  "scopes": [
    "read",
    "write"
  ]
}
```

## Referência: Conversas

### GET /public/conversations — Listar conversas

Lista as conversas que a chave pode ver, da mais recente para a mais antiga.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `status` | string | PENDING, BOT, OPEN, WAITING ou CLOSED. |
| `channelId` | string | Só conversas deste canal. |
| `contactId` | string | Só conversas deste contato. |
| `assignedToId` | string | Só conversas deste atendente. |
| `updatedSince` | string (ISO 8601) | Só conversas alteradas a partir desta data (bom para sincronizar). |
| `page` | number | Página (começa em 1). Padrão: 1. |
| `limit` | number | Itens por página, de 1 a 100. Padrão: 25. |

Exemplo de resposta (`data`):
```json
{
  "items": [
    {
      "id": "cmf3k9x1a0001",
      "status": "OPEN",
      "channelId": "cmf0abc123",
      "channelName": "Vendas",
      "channelType": "WHATSAPP_MAGICAPI",
      "contactId": "cmf2xyz789",
      "contactName": "Maria Souza",
      "contactPhone": "5571999990000",
      "assignedToId": "cmf1usr456",
      "subject": null,
      "protocol": null,
      "isGroup": false,
      "lastMessageAt": "2026-10-05T14:32:10.000Z",
      "closedAt": null,
      "createdAt": "2026-10-05T14:10:00.000Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 25
}
```

- Chaves de atendente só enxergam as conversas que o atendente pode ver no painel.

### GET /public/conversations/{id} — Buscar uma conversa

Devolve os dados de uma conversa.

Permissão: read

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador da conversa. |

Exemplo de resposta (`data`):
```json
{
  "id": "cmf3k9x1a0001",
  "status": "OPEN",
  "channelId": "cmf0abc123",
  "channelName": "Vendas",
  "channelType": "WHATSAPP_MAGICAPI",
  "contactId": "cmf2xyz789",
  "contactName": "Maria Souza",
  "contactPhone": "5571999990000",
  "assignedToId": "cmf1usr456",
  "subject": null,
  "protocol": null,
  "isGroup": false,
  "lastMessageAt": "2026-10-05T14:32:10.000Z",
  "closedAt": null,
  "createdAt": "2026-10-05T14:10:00.000Z"
}
```

### GET /public/conversations/{id}/messages — Mensagens da conversa

Histórico da conversa, da mensagem mais nova para a mais antiga. Para ir mais para trás, repita a chamada com `before` igual ao `nextBefore` recebido.

Permissão: read

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador da conversa. |

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `limit` | number | De 1 a 100. Padrão: 30. |
| `before` | string | Id de uma mensagem: devolve só as anteriores a ela. |

Exemplo de resposta (`data`):
```json
{
  "items": [
    {
      "id": "cmf7msg001",
      "direction": "INBOUND",
      "type": "TEXT",
      "status": "DELIVERED",
      "text": "Oi, quero saber o preço",
      "mediaUrl": null,
      "createdAt": "2026-10-05T14:10:05.000Z"
    }
  ],
  "nextBefore": null
}
```

- direction: INBOUND (cliente) ou OUTBOUND (empresa). nextBefore é null quando não há mais mensagens.

### POST /public/conversations/{id}/messages — Responder na conversa

Envia uma mensagem de texto dentro de uma conversa que já existe, pelo mesmo canal dela.

Permissão: write

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador da conversa. |

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `text` *(obrigatório)* | string | Texto da mensagem (até 4096 caracteres). |

Exemplo de corpo:
```json
{
  "text": "Olá! Já vou verificar para você."
}
```

Exemplo de resposta (`data`):
```json
{
  "id": "cmf7msg002",
  "status": "queued"
}
```

- No WhatsApp oficial, fora da janela de 24 horas só é possível enviar templates.

### POST /public/conversations/{id}/close — Encerrar a conversa

Encerra a conversa. Se o envio automático da pesquisa de avaliação estiver ligado, o cliente recebe o pedido de avaliação.

Permissão: write

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador da conversa. |

Exemplo de resposta (`data`):
```json
{
  "id": "cmf3k9x1a0001",
  "status": "CLOSED",
  "channelId": "cmf0abc123",
  "channelName": "Vendas",
  "channelType": "WHATSAPP_MAGICAPI",
  "contactId": "cmf2xyz789",
  "contactName": "Maria Souza",
  "contactPhone": "5571999990000",
  "assignedToId": "cmf1usr456",
  "subject": null,
  "protocol": null,
  "isGroup": false,
  "lastMessageAt": "2026-10-05T14:32:10.000Z",
  "closedAt": "2026-10-05T15:30:00.000Z",
  "createdAt": "2026-10-05T14:10:00.000Z"
}
```

## Referência: Mensagens

### POST /public/messages — Enviar mensagem para um telefone

Envia uma mensagem de texto para um número de telefone, por um canal de WhatsApp. O contato e a conversa são criados se ainda não existirem.

Permissão: write

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `channelId` *(obrigatório)* | string | Canal de WhatsApp (veja GET /public/channels). |
| `phone` *(obrigatório)* | string | Telefone com DDD. Aceita com ou sem +55 e símbolos. |
| `text` *(obrigatório)* | string | Texto da mensagem (até 4096 caracteres). |
| `name` | string | Nome do contato, usado se ele ainda não existir. |

Exemplo de corpo:
```json
{
  "channelId": "cmf0abc123",
  "phone": "(71) 99999-0000",
  "text": "Olá! Seu pedido saiu para entrega.",
  "name": "Maria Souza"
}
```

Exemplo de resposta (`data`):
```json
{
  "status": "queued",
  "conversationId": "cmf3k9x1a0001"
}
```

- Limite de 60 mensagens por minuto por chave.
- Contato que pediu para não receber mensagens: erro 409. Fora da janela de 24 h do WhatsApp oficial: erro 409.

## Referência: Contatos

### GET /public/contacts — Listar contatos

Lista os contatos da empresa, do mais novo para o mais antigo.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `search` | string | Busca por nome, e-mail ou telefone. |
| `tag` | string | Só contatos com esta tag (pelo nome). |
| `page` | number | Página (começa em 1). Padrão: 1. |
| `limit` | number | Itens por página, de 1 a 100. Padrão: 25. |

Exemplo de resposta (`data`):
```json
{
  "items": [
    {
      "id": "cmf2xyz789",
      "name": "Maria Souza",
      "phone": "5571999990000",
      "email": "maria@exemplo.com",
      "notes": null,
      "optedOut": false,
      "tags": [
        {
          "id": "cmf4tag001",
          "name": "VIP",
          "color": "#6366f1"
        }
      ],
      "createdAt": "2026-09-20T10:00:00.000Z",
      "updatedAt": "2026-10-05T14:10:00.000Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 25
}
```

### GET /public/contacts/{id} — Buscar um contato

Devolve os dados de um contato, com as tags.

Permissão: read

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador do contato. |

Exemplo de resposta (`data`):
```json
{
  "id": "cmf2xyz789",
  "name": "Maria Souza",
  "phone": "5571999990000",
  "email": "maria@exemplo.com",
  "notes": null,
  "optedOut": false,
  "tags": [
    {
      "id": "cmf4tag001",
      "name": "VIP",
      "color": "#6366f1"
    }
  ],
  "createdAt": "2026-09-20T10:00:00.000Z",
  "updatedAt": "2026-10-05T14:10:00.000Z"
}
```

### POST /public/contacts — Criar ou atualizar contato

Cria o contato, ou atualiza se já existir um com o mesmo telefone ou e-mail. Informe ao menos um dos dois.

Permissão: write

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `phone` | string | Telefone com DDD. |
| `email` | string | E-mail. |
| `name` | string | Nome. |
| `tags` | string[] | Tags a aplicar (criadas se não existirem; até 5). |

Exemplo de corpo:
```json
{
  "name": "Maria Souza",
  "phone": "71999990000",
  "email": "maria@exemplo.com",
  "tags": [
    "VIP"
  ]
}
```

Exemplo de resposta (`data`):
```json
{
  "contact": {
    "id": "cmf2xyz789",
    "name": "Maria Souza",
    "phone": "5571999990000",
    "email": "maria@exemplo.com"
  },
  "created": true
}
```

### PATCH /public/contacts/{id} — Editar contato

Altera nome, e-mail ou observações. Só os campos enviados mudam.

Permissão: write

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador do contato. |

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `name` | string | Novo nome. |
| `email` | string | Novo e-mail (vazio remove). |
| `notes` | string | Observações (vazio remove). |

Exemplo de corpo:
```json
{
  "notes": "Cliente prefere contato à tarde."
}
```

Exemplo de resposta (`data`):
```json
{
  "id": "cmf2xyz789",
  "name": "Maria Souza",
  "phone": "5571999990000",
  "email": "maria@exemplo.com",
  "notes": null,
  "optedOut": false,
  "tags": [
    {
      "id": "cmf4tag001",
      "name": "VIP",
      "color": "#6366f1"
    }
  ],
  "createdAt": "2026-09-20T10:00:00.000Z",
  "updatedAt": "2026-10-05T14:10:00.000Z"
}
```

### POST /public/contacts/{id}/tags — Adicionar tag ao contato

Aplica uma tag ao contato. A tag é criada se ainda não existir.

Permissão: write

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador do contato. |

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `tag` *(obrigatório)* | string | Nome da tag (até 40 caracteres). |

Exemplo de corpo:
```json
{
  "tag": "Lead quente"
}
```

Exemplo de resposta (`data`):
```json
{
  "id": "cmf2xyz789",
  "name": "Maria Souza",
  "phone": "5571999990000",
  "email": "maria@exemplo.com",
  "notes": null,
  "optedOut": false,
  "tags": [
    {
      "id": "cmf4tag001",
      "name": "VIP",
      "color": "#6366f1"
    }
  ],
  "createdAt": "2026-09-20T10:00:00.000Z",
  "updatedAt": "2026-10-05T14:10:00.000Z"
}
```

### DELETE /public/contacts/{id}/tags/{tag} — Remover tag do contato

Tira a tag do contato (a tag continua existindo na empresa).

Permissão: write

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador do contato. |
| `tag` *(obrigatório)* | string | Nome da tag. |

Exemplo de resposta (`data`):
```json
{
  "id": "cmf2xyz789",
  "name": "Maria Souza",
  "phone": "5571999990000",
  "email": "maria@exemplo.com",
  "notes": null,
  "optedOut": false,
  "tags": [],
  "createdAt": "2026-09-20T10:00:00.000Z",
  "updatedAt": "2026-10-05T14:10:00.000Z"
}
```

## Referência: Canais

### GET /public/channels — Listar canais

Canais (WhatsApp, Instagram, e-mail) que a chave pode usar. O `id` é o `channelId` usado ao enviar mensagens.

Permissão: read

Exemplo de resposta (`data`):
```json
{
  "items": [
    {
      "id": "cmf0abc123",
      "name": "Vendas",
      "type": "WHATSAPP_MAGICAPI",
      "isActive": true
    }
  ]
}
```

## Referência: Tags

### GET /public/tags — Listar tags

Todas as tags da empresa.

Permissão: read

Exemplo de resposta (`data`):
```json
{
  "items": [
    {
      "id": "cmf4tag001",
      "name": "VIP",
      "color": "#6366f1"
    }
  ]
}
```

### POST /public/tags — Criar tag

Cria uma tag. Se já existir uma com o mesmo nome, responde 409.

Permissão: write

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `name` *(obrigatório)* | string | Nome (até 40 caracteres). |
| `color` | string | Cor em hexadecimal, ex.: #22c55e. |

Exemplo de corpo:
```json
{
  "name": "Lead quente",
  "color": "#ef4444"
}
```

Exemplo de resposta (`data`):
```json
{
  "id": "cmf4tag002",
  "name": "Lead quente",
  "color": "#ef4444"
}
```

## Referência: Tarefas

### GET /public/tasks — Listar tarefas

Tarefas atribuídas ao dono da chave ou criadas por ele. Administradores podem pedir todas com `scope=all`.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `status` | string | OPEN ou DONE. |
| `contactId` | string | Só tarefas deste contato. |
| `scope` | string | `all` para ver as de toda a empresa (só administradores). |

Exemplo de resposta (`data`):
```json
{
  "items": [
    {
      "id": "cmf6tsk001",
      "title": "Ligar para o cliente",
      "description": null,
      "status": "OPEN",
      "dueAt": "2026-10-06T12:00:00.000Z",
      "completedAt": null,
      "assignedToId": "cmf1usr456",
      "contactId": "cmf2xyz789",
      "conversationId": null,
      "createdAt": "2026-10-05T14:40:00.000Z"
    }
  ]
}
```

### POST /public/tasks — Criar tarefa

Cria uma tarefa atribuída ao dono da chave.

Permissão: write

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `title` *(obrigatório)* | string | Título (até 200 caracteres). |
| `description` | string | Detalhes. |
| `dueAt` | string (ISO 8601) | Prazo. |
| `contactId` | string | Contato relacionado. |

Exemplo de corpo:
```json
{
  "title": "Ligar para o cliente",
  "dueAt": "2026-10-06T12:00:00Z",
  "contactId": "cmf2xyz789"
}
```

Exemplo de resposta (`data`):
```json
{
  "id": "cmf6tsk001"
}
```

### PATCH /public/tasks/{id} — Concluir ou reabrir tarefa

Muda o estado de uma tarefa.

Permissão: write

**Parâmetros de caminho**

| Nome | Tipo | Descrição |
|---|---|---|
| `id` *(obrigatório)* | string | Identificador da tarefa. |

**Corpo (JSON)**

| Nome | Tipo | Descrição |
|---|---|---|
| `status` *(obrigatório)* | string | DONE (concluída) ou OPEN (reaberta). |

Exemplo de corpo:
```json
{
  "status": "DONE"
}
```

Exemplo de resposta (`data`):
```json
{
  "id": "cmf6tsk001",
  "status": "DONE",
  "completedAt": "2026-10-05T16:00:00.000Z"
}
```

## Referência: Avaliações

### GET /public/ratings — Listar avaliações

Avaliações respondidas pelos clientes (nota do atendimento, nota do atendente e comentário), da mais recente para a mais antiga.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |
| `agentId` | string | Só avaliações deste atendente. |
| `minScore` | number | Nota mínima do atendimento (1 a 5). |
| `maxScore` | number | Nota máxima do atendimento (1 a 5). |
| `page` | number | Página (começa em 1). Padrão: 1. |
| `limit` | number | Itens por página, de 1 a 100. Padrão: 25. |

Exemplo de resposta (`data`):
```json
{
  "items": [
    {
      "id": "cmf5rat001",
      "score": 5,
      "agentScore": 4,
      "comment": "Atendimento rápido!",
      "source": "LINK",
      "respondedAt": "2026-10-05T15:00:00.000Z",
      "agentId": "cmf1usr456",
      "agentName": "João Lima",
      "conversationId": "cmf3k9x1a0001",
      "contactName": "Maria Souza"
    }
  ],
  "total": 1,
  "page": 1
}
```

- Notas de 1 a 5 estrelas: 1 = Ruim, 2 = Regular, 3 = Bom, 4 = Muito bom, 5 = Excelente.

### GET /public/ratings/summary — Resumo das avaliações

Médias, distribuição das notas, taxa de resposta e ranking por atendente no período.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |
| `agentId` | string | Só deste atendente. |

Exemplo de resposta (`data`):
```json
{
  "responses": 42,
  "sent": 80,
  "responseRate": 53,
  "avgScore": 4.5,
  "avgAgentScore": 4.6,
  "distribution": {
    "1": 1,
    "2": 2,
    "3": 4,
    "4": 12,
    "5": 23
  },
  "byAgent": [
    {
      "agentId": "cmf1usr456",
      "agentName": "João Lima",
      "responses": 20,
      "avgScore": 4.7,
      "avgAgentScore": 4.8
    }
  ]
}
```

## Referência: Painel

### GET /public/dashboard/overview — Visão geral

Totais do período, comparação com o período anterior e situação atual (abertas, pendentes etc.).

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
{
  "activeConversations": 18,
  "totalConversations": 240,
  "totalMessages": 3120,
  "avgFirstResponseMinutes": 4.2,
  "slaCompliancePercent": 96,
  "resolutionRatePercent": 88
}
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/volume-by-day — Conversas por dia

Quantidade de conversas criadas em cada dia.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
[
  {
    "date": "2026-10-04",
    "count": 31
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/volume-by-channel — Conversas por canal

Quantidade de conversas em cada canal.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
[
  {
    "channelId": "cmf0abc123",
    "name": "Vendas",
    "count": 120
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/volume-by-status — Conversas por status

Quantas conversas há agora em cada status (retrato do momento, sem período).

Permissão: read

Exemplo de resposta (`data`):
```json
[
  {
    "status": "OPEN",
    "count": 12
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/kpi-sparklines — Séries dos indicadores

Série diária dos indicadores principais (ativas, tempo de resposta, SLA, resolução).

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
{
  "active": [],
  "firstResponse": [],
  "sla": [],
  "resolution": []
}
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/agent-performance — Desempenho dos atendentes

Conversas atendidas e tempos por atendente.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
[
  {
    "agentId": "cmf1usr456",
    "name": "João Lima",
    "conversations": 54
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/volume-flow — Criadas x encerradas

Conversas criadas e encerradas por dia.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
[
  {
    "date": "2026-10-04",
    "created": 31,
    "closed": 28
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/peak-hours — Horários de pico

Mapa de calor de conversas por dia da semana e hora.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
[
  {
    "day": 1,
    "hour": 10,
    "count": 14
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/messages-flow — Mensagens por dia

Mensagens recebidas e enviadas por dia.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
[
  {
    "date": "2026-10-04",
    "inbound": 220,
    "outbound": 260
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/bot-performance — Desempenho do robô

Quanto o robô resolve sozinho e quanto passa para atendentes.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |

Exemplo de resposta (`data`):
```json
{
  "resolvedByBot": 40,
  "escalated": 12
}
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

### GET /public/dashboard/top-tags — Tags mais usadas

Ranking das tags mais aplicadas no período.

Permissão: read

**Parâmetros de consulta (query)**

| Nome | Tipo | Descrição |
|---|---|---|
| `from` | string (ISO 8601) | Início do período. Padrão: 30 dias atrás. |
| `to` | string (ISO 8601) | Fim do período. Padrão: agora. O período pode ter no máximo 1 ano. |
| `limit` | number | Quantas tags devolver. Padrão: 5. |

Exemplo de resposta (`data`):
```json
[
  {
    "tag": "VIP",
    "count": 22
  }
]
```

- O formato exato dos campos pode ganhar novos itens com o tempo; leia só o que precisa.

## Referência: Status

### GET /public/health — Saúde da API

Mostra se a API e o banco de dados estão respondendo. Não precisa de chave. Responde 503 se o banco estiver fora.

Permissão: aberta (sem chave)

Exemplo de resposta (`data`):
```json
{
  "status": "ok",
  "database": "ok",
  "latencyMs": 4,
  "time": "2026-10-05T14:00:00.000Z"
}
```