Referência: a API pública de conversas do chat, para uma tela de Conversas no seu sistema
Esta é a referência para quem quer mostrar, dentro do próprio sistema, as conversas que uma pessoa teve com o chat: um menu "Conversas" com busca, a leitura de cada conversa e o botão de continuar de onde parou, no estilo dos assistentes de IA do mercado. Se você está começando, leia antes Chat (widget do site) e Verificação de identidade. O que a pessoa vê no widget está em Conversas anteriores.
Integrando com uma IA de programação? O guia GET /api/v1/public/chat/llms.txt?key=A-CHAVE-DO-SEU-CHAT traz esta mesma referência já preenchida com a sua chave e os seus endereços, na seção "Tela Conversas no seu sistema".
O atalho: o chat como tela inteira (mode: 'page')
Se o que você quer é um item Conversas no menu do seu sistema, não precisa montar lista nenhuma: o próprio chat tem um modo de tela inteira, no formato dos assistentes de IA do mercado. Barra lateral com as conversas da pessoa (busca por texto e Nova conversa), tela inicial com as sugestões do canal e a conversa ocupando o resto. No celular a barra vira uma gaveta.
<div id="conversas" style="height: calc(100vh - 64px)"></div>
<script src="ENDERECO-DO-CHAT/widget/chat.js"
data-key="A-CHAVE-DO-SEU-CHAT"
data-mode="page"
data-container="#conversas"
data-auth="..." data-sig="..."></script>
Ou por JavaScript: Chat.init({ key, mode: 'page', container: '#conversas', auth, sig }). Sem container, a tela ocupa a janela inteira. A identidade assinada é o que faz a lista acompanhar a pessoa em qualquer navegador; sem ela, aparecem só as conversas daquele navegador.
Dois métodos acompanham o modo, para quem prefere desenhar a lista do próprio jeito e usar o chat só para a conversa: Chat.resume(token) abre o chat já numa conversa da lista (o token é o da API abaixo) e Chat.newConversation() começa outra sem encerrar a atual.
O resto desta página é para quem quer montar a lista fora do widget, com a API.
Antes de tudo: qual API é esta
A API de atendimento tem uma listagem de conversas, GET /api/v1/tickets/conversations, mas ela é do painel da sua equipe: devolve a conta inteira, de todos os seus clientes, e inclui notas internas. Ela não serve para uma tela voltada ao usuário do seu sistema, porque cada pessoa veria a conversa das outras.
A API desta página é a pública do chat, a mesma que o widget usa. Ela não recebe chave de API: quem identifica a pessoa é a identidade assinada do seu site, e por isso ela só devolve o que é daquela pessoa.
Regras que valem para todas as chamadas
- Endereço base: o mesmo da API,
https://SEU-ENDERECO-DA-API/api/v1. - Sem
Authorization. Chave de API é ignorada nestas rotas. key(obrigatório, na query string): a chave do canal de chat, a mesma dodata-keydo código de instalação.authesig(na query string, não em header): o mesmo par da Verificação de identidade.authé o payload em base64,sigé o HMAC-SHA256 hexadecimal calculado sobre o base64, com o segredo do canal.- O payload precisa ter
email. É por ele que a plataforma encontra o contato e as conversas dele.user_refousubaccount_refsozinhos não listam nada. - O escopo é a pessoa, não a empresa. Dois usuários da mesma empresa não veem as conversas um do outro.
- Identidade inválida não dá erro: a lista vem vazia, com status 200. Para a sua tela distinguir "assinatura errada" de "sem conversas", valide o par uma vez por sessão com
POST /api/v1/public/chat/verify-identityenviando{ key, auth, sig }. A resposta é{ "valid": true, "payload": {...} }ou{ "valid": false, "reason": "..." }. - A assinatura não expira. O payload não tem data; só a rotação do segredo a invalida.
1. Listar as conversas da pessoa
GET /api/v1/public/chat/conversations?key=...&auth=...&sig=...
| Parâmetro | Obrigatório | O que faz |
|---|---|---|
key | sim | chave do canal de chat |
auth, sig | sim | identidade assinada |
q | não | busca por texto no assunto e nas mensagens, termo parcial, só dentro das conversas dessa pessoa |
before | não | cursor da próxima página: o next_cursor da resposta anterior |
Não existe page, per_page nem filtro de situação. A página tem sempre 10 conversas, a janela é de 90 dias e cada conversa aparece uma vez (retomadas não duplicam).
{
"conversations": [
{
"token": "8f1c2b4e-6d3a-4a51-9b0e-2f7c1d5e9a10",
"subject": "Cadastro de fornecedor",
"preview": "Não consegui resolver isso agora. Pode reformular a pergunta?",
"last_at": "2026-08-28 23:26:15",
"status": "open"
}
],
"next_cursor": 48213
}
| Campo | Tipo | Significado |
|---|---|---|
token | texto | identifica a conversa; vai no endereço de leitura e é o resume_token para continuar |
subject | texto | assunto; nunca vazio |
preview | texto | última mensagem pública (nota interna nunca entra), texto puro, até 80 caracteres; pode ser vazio |
last_at | texto | data da última mensagem, no formato AAAA-MM-DD HH:MM:SS, em UTC |
status | open ou ended | em aberto ou encerrada |
next_cursor | número ou null | passe em before para a próxima página; null quando acabou |
2. Ler uma conversa
GET /api/v1/public/chat/conversations/{token}/messages?key=...&auth=...&sig=...
Devolve até 200 mensagens, em ordem cronológica, e só as públicas. Sem paginação. Cada mensagem tem o mesmo formato que o widget recebe:
{
"id": 91234,
"author_type": "contact",
"author": "Ana",
"visibility": "public",
"channel": "chat",
"body": "Como cadastro um fornecedor?",
"created_at": "2026-08-28T23:14:02.000000Z",
"feedbackable": false,
"feedback": null,
"agent": null,
"turn_id": null,
"quick_replies": null,
"buttons": null,
"notice": null,
"pending_action": null,
"attachments": []
}
author_type:contact(a pessoa),user(alguém da sua equipe),agent(agente de IA) ousystem.body: as respostas da IA vêm em Markdown (com tabelas); renderize.created_at: ISO 8601 em UTC. Repare que é um formato diferente dolast_atda lista.feedbackableétruesó em resposta da IA;feedbackéup,downounull. Em conversa antiga não há como registrar feedback pela API.agent:{ first_name, photo_url }quando um humano respondeu e o canal apresenta a equipe;nullno resto.attachments: lista de{ id, name, mime, size, url, kind, duration_ms, transcript }.notice: cartão de estado que o widget mostra quando a IA para, em mensagemauthor_type: "system":{ kind, title, text }.kindéidentify(precisa entrar na conta),queued(entregue à equipe) oulimit(a IA não continua e não há equipe). Nolimit, otitle"Limite de uso deste mês atingido" é o teto mensal da pessoa (user_ref) definido pelo administrador dela em Subcontas; se a sua tela quer o número,GET /subaccounts/{id}/usagetrazdebited_creditselimit_creditsporuser_ref.
3. Continuar de onde parou
POST /api/v1/public/chat/sessions
{ "key": "...", "auth": "...", "sig": "...", "resume_token": "8f1c2b4e-6d3a-4a51-9b0e-2f7c1d5e9a10" }
→ { "token": "TOKEN-DA-SESSAO-NOVA", "brand": { ... } }
Abre uma sessão nova ligada à mesma conversa. Daí em diante use o token novo em POST e GET /api/v1/public/chat/sessions/{token}/messages, exatamente como o widget faz. Se a conversa reabre ou vira um acompanhamento vinculado, é a plataforma quem decide, na primeira mensagem. O resume_token não expira.
Se o seu sistema já tem o widget instalado, Chat.openConversations() abre a mesma lista pronta dentro dele, sem chamada nenhuma.
Erros
| Situação | Status | Corpo |
|---|---|---|
key inválida | 404 | { "error": "widget_not_found" } |
auth/sig ausente, inválido ou assinado com segredo antigo | 200 | { "conversations": [], "next_cursor": null } |
token que não é dessa pessoa, inexistente ou de outro canal | 404 | { "error": "not_found" } (nunca 403, para não confirmar que a conversa existe) |
| acima do limite de chamadas | 429 | { "message": "Too Many Attempts." } |
Limites
- Limite por IP e por rota, não por pessoa: listar 30 por minuto, ler 60, abrir sessão 10, validar identidade 20.
- Se o seu servidor chama em nome de todos os usuários, ele compartilha um IP só. Chame no clique do menu, nunca na carga da página, e guarde a lista alguns segundos por usuário.
- 10 conversas por página, 200 mensagens por conversa, 90 dias de janela.
Perguntas frequentes
Dá para listar as conversas da empresa inteira, e não só do usuário? Hoje não. A lista é da pessoa identificada. Para uma visão da equipe, o lugar é o painel, em Atendimento › Conversas.
Por que a identidade errada não devolve erro? Porque o histórico é dado pessoal. Uma resposta diferente para "assinatura errada" e "essa pessoa não existe" ajudaria alguém a testar identidades. Use o verify-identity para validar o seu código.
A chave de API da minha conta funciona aqui? Não, e nem deve: ela daria acesso a tudo. Estas rotas só entendem a identidade assinada.