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

# Consultar logs

> Endpoint query-message-logs: histórico de envios da conta com filtros por tag, canal, status, comunicação e período

O endpoint [`GET /query-message-logs`](https://docs.octasend.com.br/api-reference/query-message-logs) devolve o histórico de envios da sua conta, do mais recente para o mais antigo, com paginação. É o mesmo histórico que aparece em [Logs](https://docs.octasend.com.br/plataforma/logs-de-mensagens.md) no painel: inclui os envios feitos pela API, por campanhas, automações e pelo próprio painel. Cada envio de campanha gera um registro; envios de campanha antigos podem aparecer em dois.

Todos os parâmetros são opcionais e vão na query string.

```http theme={null}
GET https://api.octasend.com.br/functions/v1/query-message-logs?tag=onboarding&channel=email&status=sent&from=2026-01-01T00:00:00Z&to=2026-01-31T23:59:59Z&page=1&limit=20
Authorization: Bearer at_f4a92b...
```

> [!NOTE]
>
> **Autenticação:** a mesma do `send-message` — access token ou o par `client_id:client_secret`. Veja [Autenticação](https://docs.octasend.com.br/api-reference/autenticacao.md).

## Parâmetros de consulta

| Parâmetro | Tipo | Padrão | Descrição |
| - | - | - | - |
| `tag` | string | — | Devolve os envios que têm esta tag, entre as tags de cada envio. Uma tag por consulta. Ex.: `?tag=onboarding` |
| `channel` | string | — | Canal: `email`, `whatsapp`, `sms`, `telegram`, `slack`, `web_push`, `in_app` ou `push` |
| `status` | string | — | Status: `queued`, `processing`, `sent`, `delivered`, `read`, `failed` ou `skipped` |
| `communication_slug` | string | — | Slug da comunicação. Um slug que não existe na conta devolve lista vazia, sem erro |
| `from` | string (ISO 8601) | — | Envios criados a partir desta data e hora, inclusive |
| `to` | string (ISO 8601) | — | Envios criados até esta data e hora, inclusive |
| `page` | número | `1` | Página. Valores menores que 1 viram 1 |
| `limit` | número | `20` | Itens por página, de 1 a 100. Valores acima de 100 viram 100 |

Os filtros se combinam: a consulta devolve só os envios que atendem a todos os parâmetros informados.

Em `from` e `to`, um horário sem fuso (ex.: `2026-01-01T00:00:00`) é lido em UTC. Para usar o dia no fuso da conta, como na tela **Logs**, informe o deslocamento (ex.: `2026-01-01T00:00:00-03:00`).

## Resposta

```json theme={null}
{
  "data": [
    {
      "id": "3f1c2b9e-...",
      "channel": "email",
      "status": "sent",
      "recipient_email": "usuario@exemplo.com",
      "recipient_phone": null,
      "language_code": "pt-BR",
      "tag": ["onboarding", "junho-2024"],
      "variables": { "nome": "Ricardo" },
      "provider_message_id": "010f018e...",
      "error_message": null,
      "sent_at": "2026-01-10T10:00:01Z",
      "delivered_at": "2026-01-10T10:00:03Z",
      "read_at": "2026-01-10T10:12:40Z",
      "clicked_at": null,
      "created_at": "2026-01-10T10:00:00Z"
    }
  ],
  "total": 150,
  "page": 1,
  "limit": 20
}
```

| Campo | Descrição |
| - | - |
| `data` | Envios da página, do mais recente para o mais antigo |
| `total` | Total de envios que atendem aos filtros, somando todas as páginas |
| `page` | Página devolvida |
| `limit` | Itens por página usados na consulta |

Principais campos de cada envio:

| Campo | Descrição |
| - | - |
| `id` | Identificador do registro — o mesmo `log_id` devolvido pelo `send-message` |
| `channel` | Canal do envio |
| `status` | Status atual (tabela abaixo) |
| `recipient_email` / `recipient_phone` | Destinatário, quando informado |
| `language_code` | Idioma do template usado |
| `tag` | Lista de tags do envio, ou `null` |
| `variables` | Variáveis enviadas |
| `sent_content` | Conteúdo da mensagem **já com as variáveis preenchidas**, como o destinatário recebeu. Formato por canal na seção [Conteúdo enviado](#conteudo-enviado). É `null` em envios antigos |
| `provider_message_id` | Identificador devolvido pelo provedor |
| `error_message` | Motivo da falha ou do descarte |
| `error_code` | Código do erro, quando há: o código informado pelo provedor (ex.: código da Meta, evento do SendGrid) ou `daily_limit_reached`, quando o envio foi recusado pelo limite diário da conta |
| `sent_at` | Quando o provedor aceitou a mensagem |
| `delivered_at` | Quando a entrega foi registrada. No e-mail, vem da entrega informada pelo SendGrid; sem ela, da primeira abertura |
| `read_at` | Quando a leitura foi registrada: no WhatsApp, a confirmação de leitura; no e-mail, a primeira abertura |
| `clicked_at` | Quando um clique foi registrado (e-mail e Web Push) |
| `created_at` | Quando o registro foi criado |

Cada registro pode trazer outros campos além destes. As datas vêm em UTC; a tela **Logs** mostra as mesmas datas no fuso horário da conta.

## Conteúdo enviado

`sent_content` guarda o texto final de cada mensagem. Vale como registro de auditoria mesmo que o template seja editado depois. O formato depende do canal:

| Canal | `sent_content` |
| - | - |
| `email` | `{ "subject", "body_html", "body_text" }` |
| `push`, `web_push`, `in_app` | `{ "title", "body_text" }` |
| `whatsapp` | `{ "messages": [ { "body_text", "status", … } ] }` |
| `telegram`, `slack`, `sms` | `{ "body_text" }` |

Vem `null` em mensagens enviadas antes do registro do conteúdo ou quando a mensagem não gerou texto.

## Uma mensagem pelo id

`GET /query-message-logs?id=<message_id>` devolve uma única mensagem, no mesmo formato de um item da lista, dentro de `{ "data": { … } }`. O `message_id` é o devolvido pelo `send-message` em cada resultado.

```bash theme={null}
curl "https://api.octasend.com.br/functions/v1/query-message-logs?id=3f1c2b9e-..." \
  -H "Authorization: Bearer SEU_ACCESS_TOKEN"
```

Um `id` que não é UUID responde `400`; um id inexistente ou de outra conta responde `404`. No [servidor MCP](https://docs.octasend.com.br/api-reference/mcp-server.md), use as tools `get_message` (pelo id) e `list_messages` (com os filtros acima).

## Status de um envio

| Status | Significado |
| - | - |
| `queued` | Enfileirada — aguardando envio (ex.: fila de WhatsApp) |
| `processing` | Em processamento |
| `sent` | Enviada — o provedor aceitou a mensagem |
| `delivered` | Entregue — confirmação do WhatsApp enviado pela Evolution API |
| `read` | Lida — confirmação do WhatsApp enviado pela Evolution API |
| `failed` | Falhou — veja `error_message`. Inclui o envio recusado pelo limite diário da conta (`Limite diário de mensagens atingido`) |
| `skipped` | Ignorada — faltou dado do destinatário, não havia template no idioma, o número não tem WhatsApp, o canal In-App está desabilitado, o contato se descadastrou do canal (`Contato descadastrado`, em campanhas, automações de marketing e envios pela API com `respect_opt_out: true`) ou, em campanhas, o contato foi removido em **Contatos** antes de a mensagem sair (`Contato removido`) |

O registro continua mudando depois do envio, conforme o provedor informa o que aconteceu:

* **WhatsApp oficial (Meta):** o status fica `sent`; a confirmação de entrega preenche `delivered_at` e a de leitura, `read_at`. Se a Meta recusar a entrega, o status vai para `failed`.
* **WhatsApp pela Evolution API:** com a fila ligada, sai de `queued` para `sent`, `failed` ou `skipped` quando a mensagem deixa a fila. Depois do envio, avança para `delivered` (com `delivered_at`) e `read` (com `read_at`) conforme o WhatsApp confirma. O status só avança: uma confirmação atrasada não volta uma mensagem lida para entregue.
* **E-mail:** a entrega informada pelo SendGrid preenche `delivered_at`, a primeira abertura preenche `read_at` e o clique preenche `clicked_at`, mantendo o status `sent`. Abrir ou clicar também preenche o que ainda estiver vazio: sem entrega registrada (por exemplo, no Amazon SES e no SMTP), a primeira abertura preenche `delivered_at`. Os eventos `bounce`, `dropped` e `deferred` informados pelo SendGrid mudam o status para `failed`, com o nome do evento em `error_code`. Os eventos `spamreport`, `unsubscribe` e `group_unsubscribe` não mudam o status, porque a mensagem foi entregue: eles descadastram o contato do e-mail.
* **Web Push:** o recebimento preenche `delivered_at` e o clique, `clicked_at`.
* **SMS:** a confirmação de entrega preenche `delivered_at`; se o provedor informar que não entregou, o status vira `failed`. Na Twilio, a confirmação chega quando a Twilio avisa a plataforma; na SendPulse, a plataforma consulta a entrega a cada 2 minutos, para os SMS enviados nas últimas 48 horas.

> [!TIP]
>
> Para acompanhar um disparo específico, envie uma `tag` própria no `send-message` (ex.: `pedido-12345`) e consulte por ela depois. Isso vale também para mensagens adiadas pelo limite por minuto, que não trazem resultado na resposta do envio.

## Erros

| HTTP | `error` | Causa |
| - | - | - |
| 400 | `id` inválido | Com `?id=`, o valor não é um UUID |
| 404 | não encontrada | Com `?id=`, a mensagem não existe na conta |
| 401 | `Authorization header required` | Header `Authorization` ausente ou sem o prefixo `Bearer` |
| 401 | `Invalid, expired or revoked token` | Token vencido, client revogado ou credencial inválida |
| 500 | `Database query failed` | A consulta não pôde ser feita — confira se `from` e `to` estão em formato ISO 8601 válido |

## Exemplos

```bash cURL theme={null}
curl "https://api.octasend.com.br/functions/v1/query-message-logs?tag=onboarding&status=failed&limit=50" \
  -H "Authorization: Bearer SEU_ACCESS_TOKEN"
```

```typescript Node.js (todas as páginas) theme={null}
const BASE_URL = 'https://api.octasend.com.br/functions/v1'

async function fetchAllLogs(token: string, filters: Record<string, string>) {
  const all: unknown[] = []
  let page = 1

  while (true) {
    const qs = new URLSearchParams({ ...filters, page: String(page), limit: '100' })
    const res = await fetch(`${BASE_URL}/query-message-logs?${qs}`, {
      headers: { Authorization: `Bearer ${token}` },
    })
    if (!res.ok) throw new Error(`Erro ${res.status}: ${await res.text()}`)

    const { data, total } = await res.json()
    all.push(...data)
    if (all.length >= total || data.length === 0) break
    page++
  }

  return all
}
```


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