Inbox pela API
A inbox é onde a equipe atende pelo painel. A API dá acesso às mesmas conversas, para ligar um helpdesk, um CRM ou um bot: o que a sua integração responde aparece para a equipe, e o que a equipe responde aparece para a sua integração.
Ler as conversas
curl 'https://api.joinotify.com/inbox/conversations?folder=open&unread=true' \
-H 'Authorization: Bearer sk_live_xxx'
A lista é paginada por cursor: mande o nextCursor da resposta em cursor para a
próxima página, até ele vir null. As mensagens de uma conversa vêm em
GET /inbox/conversations/{id}/messages, da mais recente à mais antiga, com o cursor em
before.
Cada conversa diz se a janela de 24 horas está aberta (windowOpen) e até quando
(windowExpiresAt). É isso que decide o que dá para responder.
Responder
curl -X POST https://api.joinotify.com/inbox/conversations/cm1c0nv000001/messages \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{ "kind": "text", "text": "Oi, Ana! Seu pedido saiu para entrega." }'
kind | Quando usar |
|---|---|
text | Texto livre, com a janela aberta |
media | Um arquivo, com a janela aberta — suba antes em /media |
template | Janela fechada: um template aprovado reabre a conversa |
note | Nota interna para a equipe; nunca vai para o WhatsApp |
Com a janela fechada, text e media são recusados antes de sair, com
422 window_closed — diferente de POST /messages, que aceita e falha depois. Responder
reabre uma conversa fechada ou adiada e pausa as automações daquela conversa por um tempo,
como quando alguém da equipe assume.
Para mandar um arquivo, envie os bytes em POST /inbox/conversations/{id}/media (o corpo
é o arquivo, não multipart, com o nome em X-File-Name) e responda com
{ "kind": "media", "assetId": "..." }.
Organizar
PATCH /inbox/conversations/{id} fecha, reabre, deixa pendente, adia até uma data,
atribui a alguém da equipe (os ids vêm de GET /inbox/agents) ou pausa as automações. Cada
mudança fica registrada na conversa, e fechar e atribuir disparam os eventos
conversation.closed e conversation.assigned.
Uma API key não é uma pessoa da equipe: a pasta mine vem sempre vazia, e nos eventos
assigned_by e closed_by vêm null quando quem agiu foi a chave.
Tempo real
GET /inbox/stream é um stream Server-Sent Events. Ele avisa o que mudou — mensagem
nova, status de mensagem, conversa atualizada, alguém digitando —, sem o conteúdo:
event: message.created
id: 12
data: {"type":"message.created","conversationId":"cm1c0nv000001","phoneNumberId":"106540352242922","messageId":"cm1m3ss4g3001","direction":"in"}
Ao receber um evento, busque a conversa ou as mensagens. Três cuidados:
- Não há reenvio. Um evento perdido durante uma queda não volta, e
Last-Event-IDnão recupera nada. A cada reconexão, releia as conversas que importam. - O
EventSourcedo navegador não manda o headerAuthorization. Use um cliente que mande — o stream foi feito para servidores. - Cada API key abre no máximo 5 streams ao mesmo tempo.
Se você só precisa reagir a mensagens recebidas, o webhook de
messages continua sendo o caminho mais simples.
Escopo da chave
Uma API key restrita a alguns números só vê as conversas desses números — uma conversa de
outro número responde 404, como se não existisse. GET /inbox/agents, que lista a equipe
da conta com os e-mails, responde 403 para ela.