# Ler as conversas (WhatsApp e E-mail) de um lead

> Liste as conversas de um lead por canal e puxe as mensagens de cada thread para registrar o histórico de contato onde você quiser.

- URL canônica: https://docs.growthstation.app/docs/api/guias/ler-conversas
- Idioma: pt-BR
- Última atualização: 2026-09-20T08:21:20.450Z
- Produto: GS Engage
- Mantido por: Produto GS Engage



<PageHero emoji="💬" title="Ler as conversas de um lead" description="Acesse as trocas de WhatsApp e E-mail do GS Engage e leve o histórico para o seu sistema." gradient="brand" />

Você quer ter, em outro lugar (um CRM, um data warehouse, uma planilha, um relatório), o histórico completo do que foi conversado com cada lead. As mensagens de WhatsApp e E-mail que acontecem dentro do GS Engage podem ser lidas pela API e copiadas para onde você precisar.

Esta página mostra como fazer isso em dois passos: primeiro você lista as **conversas** (chamamos de *threads*), depois puxa as **mensagens** de cada uma.

<Callout type="tip">
  Estas são operações de **leitura** (GET). Elas não enviam nada, não respondem ninguém e não alteram o lead. É seguro experimentar à vontade — nenhuma mensagem sai para o cliente.
</Callout>

💡 Antes de começar [#-antes-de-começar]

Você vai precisar de uma **apiKey** (a sua chave de acesso à API). Ela é criada na plataforma em <TextHighlight>Configurações > Configurações de API</TextHighlight> e é enviada como parâmetro na própria URL, no formato `?apiKey=SUA_CHAVE`.

<Callout type="warning" title="Sua apiKey é uma senha">
  Como a chave vai na URL, ela aparece em logs de servidor, no histórico do navegador e em qualquer link compartilhado. Guarde-a numa variável de ambiente e nunca cole em canais públicos (chat, e-mail, tickets).
</Callout>

Se ainda não validou sua chave, dê uma passada rápida pelo [Quickstart da API](/docs/api/comece-aqui/quickstart) — lá explicamos como confirmar que a chave funciona antes de qualquer outra chamada.

🧩 Como o GS Engage organiza as conversas [#-como-o-gs-engage-organiza-as-conversas]

O modelo é simples e tem dois níveis:

<Mermaid
  chart={`graph LR
A["Lead"] --> B["Thread (uma conversa por canal)"]
B --> C["Mensagem"]
B --> D["Mensagem"]
B --> E["Mensagem"]`}
/>

* **Thread** é uma conversa — um fio de diálogo por canal. Um mesmo lead pode ter uma thread de **WhatsApp** e outra de **E-mail**.
* **Mensagem** é cada troca dentro daquela thread (o que foi enviado e o que foi recebido).

Por isso a leitura acontece em duas etapas: você lista as threads para descobrir *quais conversas existem* e, com o identificador de cada uma, puxa as *mensagens* dela.

<Callout type="info" title="O que é um endpoint?">
  *Endpoint* é só o endereço de uma função da API — a "porta" que você chama para pedir ou enviar dados. Aqui usamos dois: um que lista threads e outro que lista mensagens de uma thread.
</Callout>

🚀 Passo a passo [#-passo-a-passo]

<Steps>
  <Step num={1} title="Liste as conversas (threads)">
    Comece descobrindo quais conversas existem. Chame `GET /api/v1/conversations/threads`.

    ```bash
    curl "https://api.gsengage.com/api/v1/conversations/threads?apiKey=SUA_CHAVE&limit=20&page=1"
    ```

    A resposta vem paginada, no formato padrão da API: uma lista em `data` e um resumo em `meta`.

    ```json
    {
      "data": [
        {
          "id": "652f1a9c8b3e4c0012a4d7f1",
          "channel": "WHATSAPP",
          "leadId": "651a0b2f4d9c1e0033b8e5a2"
        },
        {
          "id": "652f1b3e8b3e4c0012a4d802",
          "channel": "EMAIL",
          "leadId": "651a0b2f4d9c1e0033b8e5a2"
        }
      ],
      "meta": {
        "limit": 20,
        "count": 2,
        "total": 2,
        "page": 1,
        "totalPages": 1
      }
    }
    ```

    Guarde o `id` da thread que te interessa — é ele que você usa no próximo passo.
  </Step>

  <Step num={2} title="Puxe as mensagens de uma thread">
    Com o `id` da thread em mãos, peça as mensagens dela em `GET /api/v1/conversations/threads/{threadId}/messages`.

    ```bash
    curl "https://api.gsengage.com/api/v1/conversations/threads/652f1a9c8b3e4c0012a4d7f1/messages?apiKey=SUA_CHAVE&limit=50&page=1"
    ```

    A resposta traz o conteúdo trocado naquela conversa, também paginado.

    ```json
    {
      "data": [
        {
          "id": "6531c04a8b3e4c0012a4e910",
          "content": "Olá! Vi que você baixou nosso material. Posso ajudar?"
        },
        {
          "id": "6531c07d8b3e4c0012a4e922",
          "content": "Oi! Sim, queria entender os planos."
        }
      ],
      "meta": {
        "limit": 50,
        "count": 2,
        "total": 2,
        "page": 1,
        "totalPages": 1
      }
    }
    ```

    Pronto: essas são as mensagens da conversa, prontas para serem salvas onde você quiser.
  </Step>
</Steps>

📄 Paginação: como pegar tudo sem faltar nada [#-paginação-como-pegar-tudo-sem-faltar-nada]

As duas chamadas usam a mesma paginação. Você controla o tamanho da página com `limit` e navega com `page`.

| Parâmetro | Para que serve                   | Exemplo    |
| --------- | -------------------------------- | ---------- |
| `limit`   | Quantos itens por página         | `limit=50` |
| `page`    | Qual página buscar (começa em 1) | `page=2`   |

No bloco `meta` da resposta você tem tudo para saber se acabou:

| Campo em `meta` | O que significa                    |
| --------------- | ---------------------------------- |
| `limit`         | O tamanho de página que você pediu |
| `count`         | Quantos itens vieram nesta página  |
| `total`         | Total de itens em todas as páginas |
| `page`          | A página atual                     |
| `totalPages`    | Quantas páginas existem no total   |

A regra é: continue incrementando `page` **enquanto `page` for menor que `totalPages`**. Quando chegarem iguais, você leu tudo.

<Callout type="tip">
  Você também pode ordenar os resultados com `orderBy` e `orderDirection` (`asc` para crescente, `desc` para decrescente) — útil para trazer as mensagens em ordem cronológica.
</Callout>

🛠️ Caso de uso: registrar o histórico de contato num sistema externo [#️-caso-de-uso-registrar-o-histórico-de-contato-num-sistema-externo]

Este é o cenário mais comum: você quer que o histórico de conversas do GS Engage também apareça no seu CRM, num data warehouse ou num relatório. A lógica é sempre a mesma.

<Steps>
  <Step num={1} title="Liste todas as threads">
    Percorra `GET /api/v1/conversations/threads` página a página até `page` alcançar `totalPages`. Assim você tem todas as conversas, de todos os canais.
  </Step>

  <Step num={2} title="Para cada thread, puxe as mensagens">
    Use o `id` de cada thread em `GET /api/v1/conversations/threads/{threadId}/messages`, também paginando até o fim.
  </Step>

  <Step num={3} title="Grave no seu sistema">
    Salve as mensagens vinculadas ao `leadId` da thread. Numa próxima execução, você repete o processo e atualiza só o que for novo.
  </Step>
</Steps>

Um esqueleto em Python que amarra as duas chamadas:

```python
import os
import requests

BASE = "https://api.gsengage.com/api/v1"
API_KEY = os.environ["GSENGAGE_API_KEY"]  # nunca escreva a chave no código

def get_pages(path):
    """Percorre todas as páginas de um endpoint paginado e devolve os itens."""
    page = 1
    while True:
        resp = requests.get(
            f"{BASE}{path}",
            params={"apiKey": API_KEY, "limit": 50, "page": page},
        )
        resp.raise_for_status()
        body = resp.json()
        for item in body["data"]:
            yield item
        meta = body["meta"]
        if meta["page"] >= meta["totalPages"]:
            break
        page += 1

# 1) Todas as conversas
for thread in get_pages("/conversations/threads"):
    # 2) Todas as mensagens de cada conversa
    for message in get_pages(f"/conversations/threads/{thread['id']}/messages"):
        # 3) Aqui você grava no seu sistema, vinculando ao lead
        salvar_no_seu_sistema(thread["leadId"], thread["channel"], message)
```

<Callout type="warning" title="Cuidado com o rate limit">
  A API permite **200 requisições de leitura por minuto** (janela fixa de 60s). Como este caso faz muitas chamadas seguidas, é fácil esbarrar no limite quando há muitas threads. *Rate limit* é o teto de chamadas que você pode fazer num intervalo.
</Callout>

🚦 Quando você bate no limite (HTTP 429) [#-quando-você-bate-no-limite-http-429]

Se passar do teto, a API responde com **429** e alguns cabeçalhos que te dizem exatamente quanto esperar:

| Cabeçalho               | O que informa                                    |
| ----------------------- | ------------------------------------------------ |
| `Retry-After`           | Quantos segundos esperar antes de tentar de novo |
| `X-RateLimit-Limit`     | Seu teto de requisições na janela                |
| `X-RateLimit-Remaining` | Quantas ainda restam                             |
| `X-RateLimit-Reset`     | Quando a janela reinicia                         |

<DoDont>
  <DoDontItem type="do">
    Respeite o 

    `Retry-After`

     e faça 

    *backoff exponencial*

     (espere um pouco mais a cada nova tentativa).
  </DoDontItem>

  <DoDontItem type="dont">
    Não fique repetindo a mesma chamada em looping imediato — isso só prolonga o bloqueio.
  </DoDontItem>

  <DoDontItem type="do">
    Use um 

    `limit`

     maior (ex.: 50) para trazer mais itens por chamada e reduzir o número de requisições.
  </DoDontItem>

  <DoDontItem type="dont">
    Não puxe tudo o tempo todo — grave o que já leu e, nas próximas execuções, atualize só o que mudou.
  </DoDontItem>
</DoDont>

🔎 Como reagir aos erros [#-como-reagir-aos-erros]

As mensagens de erro do GS Engage já vêm em português — leia-as com atenção, elas costumam dizer o que corrigir.

| Código  | O que houve                | Como resolver                                                          |
| ------- | -------------------------- | ---------------------------------------------------------------------- |
| **401** | apiKey ausente ou inválida | Confira se você incluiu `?apiKey=...` na URL e se a chave está correta |
| **404** | Thread não encontrada      | Verifique o `threadId` — ele precisa ter vindo da listagem de threads  |
| **429** | Você passou do rate limit  | Espere o tempo do `Retry-After` e tente de novo com backoff            |

O corpo de um erro **400** segue o formato abaixo, apontando o campo problemático:

```json
{
  "error": {
    "message": "Descrição do que deu errado.",
    "errors": [
      { "field": ["page"], "message": "Deve ser um número maior que zero." }
    ]
  }
}
```

❓ Perguntas frequentes [#-perguntas-frequentes]

<FAQ>
  <FAQItem question="Um lead pode ter mais de uma conversa?">
    Pode. Cada canal tem sua própria thread — por exemplo, uma de **WHATSAPP** e outra de **EMAIL** para o mesmo lead. Por isso vale listar todas as threads antes de puxar as mensagens.
  </FAQItem>

  <FAQItem question="Consigo filtrar só as conversas de WhatsApp ou só de E-mail?">
    Os canais disponíveis são **WHATSAPP** e **EMAIL**. Ao listar as threads você recebe o `channel` de cada uma e pode selecionar no seu lado apenas o canal que interessa.
  </FAQItem>

  <FAQItem question="Ler as mensagens envia alguma coisa para o cliente?">
    Não. Estes endpoints são somente leitura. Nada é enviado, respondido ou alterado — você só consulta o histórico que já existe.
  </FAQItem>

  <FAQItem question="Preciso de código para isso?">
    Não necessariamente. Ferramentas no-code como **Zapier**, **Make** e **n8n** conseguem consumir a API REST do GS Engage e mover esses dados para outros sistemas sem você escrever código.
  </FAQItem>
</FAQ>

✅ Checklist antes de rodar em produção [#-checklist-antes-de-rodar-em-produção]

<Callout type="danger" title="Toda chamada é real">
  Não existe ambiente de testes (sandbox) separado no GS Engage. Toda chamada atinge dados de produção. Como aqui só fazemos leitura, o risco é baixo — mas mantenha o cuidado com a chave e com o volume de requisições.
</Callout>

<Checklist id="ler-conversas-pre-check" title="Antes de integrar">
  <ChecklistItem>
    Minha apiKey está numa variável de ambiente, fora do código?
  </ChecklistItem>

  <ChecklistItem>
    Estou paginando até 

    `page`

     alcançar 

    `totalPages`

     para não perder mensagens?
  </ChecklistItem>

  <ChecklistItem>
    Tenho tratamento para o 

    **429**

    , respeitando o 

    `Retry-After`

    ?
  </ChecklistItem>

  <ChecklistItem>
    Estou vinculando cada mensagem ao 

    `leadId`

     da thread ao salvar?
  </ChecklistItem>
</Checklist>

Artigos Relacionados [#artigos-relacionados]

<RelatedArticles>
  <RelatedArticle href="/docs/api/comece-aqui/quickstart" title="Quickstart da API" description="Crie e valide sua apiKey em poucos minutos." />

  <RelatedArticle href="/docs/api/referencia" title="Listar e filtrar leads" description="Encontre os leads cujas conversas você quer ler." />

  <RelatedArticle href="/docs/api/webhooks" title="Receber eventos por webhook" description="Seja avisado em tempo real quando algo acontece com o lead." />
</RelatedArticles>
