Eventos
Os eventos avisam o que acontece na inbox, na hora: mensagem nova, mudança de status, edição, reação. Eles
chegam por GET /events, uma conexão aberta (SSE), e pelo webhook, com os
mesmos eventos e o mesmo formato.
Conectar
curl -N "https://<subdomínio>.orkesio.com/events?events=message.received,message.status" \
-H "token: <token da inbox>"
events: os eventos que você quer, separados por vírgula. Semevents, chegam todos, menosstatus_post.received(os Status de todos os contatos),newsletter.updatedenewsletter.message(os canais) ehistory.batch(o histórico em lotes), que só vêm pedidos pelo nome.- Só os nomes da Orkesio (com ponto). Um nome da uazapi (
messages) responde400: para os eventos da uazapi, use o/sse, que continua igual. exclude: o mesmo filtro do webhook, com os mesmos valores.exclude=sent_by_apitira as mensagens enviadas pela api. Os valores:sent_by_api,not_sent_by_api,out,in,groupsenot_groups. Valor que não existe, ouinjunto comout, responde400.- Ao conectar, chega a linha
: connected(um comentário do SSE, que oEventSourcedo navegador ignora).
Com o EventSource (navegador), cada evento chega no onmessage, e o tipo está dentro do JSON. O EventSource não
manda headers; o token pode ir na URL (?token=), mas aí ele fica no histórico e nos logs. Prefira conectar pelo seu
servidor e repassar ao navegador.
const source = new EventSource("https://<subdomínio>.orkesio.com/events?events=message.received&token=<token>");
source.onmessage = (e) => {
const event = JSON.parse(e.data);
if (event.type === "message.received") mostrar(event.data);
};
O formato
Cada evento chega como duas linhas do SSE: o id do evento e o data, um JSON com o envelope:
id: evt_01JAB3K9ZQ7V0M4T8R2X6WYD5H
data: {"id":"evt_01JAB3K9ZQ7V0M4T8R2X6WYD5H","type":"message.received","created_at":"2026-10-17T12:00:00.000Z","inbox":{...},"data":{...}}
| Campo | O que é |
|---|---|
id | Id do evento: evt_ + 26 letras, em ordem de criação. Use para descartar repetidos. |
type | O evento (message.received, message.status...). |
created_at | Quando o evento aconteceu (ISO 8601, UTC). |
inbox | A inbox: id, name, phone (o número, só no WhatsApp), account_id (a Página, a conta ou o bot, nos outros canais) e channel (whatsapp_web, whatsapp_cloud, messenger, instagram ou telegram). |
data | O conteúdo, com formato fixo por type (tabela abaixo). |
O envelope é o mesmo do webhook: quem trata um, trata o outro.
Os eventos de mensagem
| Evento | Quando chega | data |
|---|---|---|
message.received | O contato mandou uma mensagem. | message (a mensagem), chat (a conversa, com o lead_id) e lead (só em conversa direta) |
message.sent | Uma mensagem da inbox saiu: pela API, por automação, pelo celular ou por outro aparelho (sent_by diz qual). | message, chat e lead, como em message.received |
message.status | Uma mensagem da inbox foi entregue, lida, ouvida ou falhou. | chat, status, at e messages (os ids); error na falha |
message.failed | Só as falhas: uma mensagem da inbox não saiu (recusada, fora do prazo, cancelada ou da campanha). Para quem só quer saber dos problemas. | message (com status: failed e o error) e chat (id, lid, type, name) |
group.receipts | Participantes de um grupo receberam ou leram uma mensagem da inbox. Em lote, a cada 60 segundos. | chat, message e receipts (quem, o quê, quando) |
message.updated | Uma mensagem mudou: editada, apagada, fixada, desafixada, transcrita ou com a mídia pronta. | change (o que mudou), message (já com a mudança) e chat |
message.reaction | Alguém reagiu a uma mensagem, ou tirou a reação. | message (a reação, como mensagem com type: reaction) e chat |
Os demais eventos
| Evento | Quando chega | data |
|---|---|---|
chat.updated | Uma conversa mudou: arquivada, fixada, silenciada, etiquetas, não lidas, automação, efêmeras, bloqueio, nome. Também quando a conversa aparece pela primeira vez (changes vazio). Para quem recebe o message.received e o message.sent, a mensagem nova não gera este evento só pelas não lidas e pela vez: elas vêm no data.chat deles. | chat (o estado novo) e changes (o que mudou) |
chat.presence | O contato ficou online ou offline, ou está digitando, gravando áudio ou parou. | chat, state; no grupo, participant; last_seen_at no offline, quando o contato mostra |
inbox.status | A conexão da inbox mudou: conectando, QR code ou código de pareamento pronto, conectada, desconectada, deslogada ou banida. | status; qr_code ou pair_code para mostrar; reason e banned_until na queda |
label.updated | Uma etiqueta do WhatsApp Business foi criada, editada ou apagada. | action, id, name, color (na exclusão, só action e id) |
call.updated | Ligação tocando, atendida, recusada, encerrada ou perdida. | a ligação: id, chat, author, direction, status, at; video quando se sabe e duration_seconds na encerrada |
status_post.received | Um contato postou um Status. Só chega pedido pelo nome. | message (a mensagem do Status) |
newsletter.updated | As visualizações ou reações dos posts de um canal mudaram, depois de POST /newsletters/{newsletter_id}/live-updates e enquanto a assinatura vale. Só chega pedido pelo nome. | newsletter_id e posts (server_id, reactions e views só quando muda) |
O que não chega aqui:
- Registros do grupo e do sistema (alguém entrou, o nome mudou) não chegam como
message.received, para não disparar automação que espera uma mensagem de verdade. Eles ficam na busca (category=event). - Publicações de Status (
status@broadcast) não chegam nos eventos de mensagem: chegam emstatus_post.received, pedido pelo nome. - O recibo de leitura das mensagens recebidas (quando você as lê pelo celular) não chega em
message.status, que é só das mensagens da inbox.
Ordem, repetição e quedas
- Ordem: os eventos de uma inbox saem na ordem em que acontecem.
- Repetição: use o
iddo evento para descartar um repetido. - Sem reenvio: se a conexão cair, os eventos desse intervalo não são reenviados. Ao reconectar:
- mensagens novas: busque com
GET /messagesusandoaftercom a hora do último evento recebido; - mudanças em mensagens antigas (status, edição, reação, apagada): o
afterfiltra pela hora em que a mensagem foi enviada, não pela hora da mudança. Uma mensagem enviada às 10h e lida às 12h, durante a queda, não volta emafter=12h. Para elas, consulte de novo as que ainda importam (por exemplo, as suas enviadas ainda semread, comidou comdirection=outno período).
- mensagens novas: busque com
- Cliente lento: cada conexão tem uma fila curta. Se o cliente não lê, os eventos que não cabem são descartados; leia sem bloquear e processe à parte.
Webhook
O webhook entrega os mesmos eventos, com o mesmo envelope, por POST no seu endereço. As rotas
ficam em /webhooks; os webhooks da uazapi (/webhook) continuam iguais e separados.
Criar
POST /webhooks
{
"name": "CRM",
"url": "https://crm.exemplo.com/whatsapp",
"events": ["message.received", "message.status"],
"retries": 3,
"headers": { "Authorization": "Bearer seu-token" }
}
- Até 5 webhooks por inbox.
events: os nomes da Orkesio (com ponto). O formato da entrega é o envelope desta página.url:https://(recomendado) ouhttp://, sempre em endereço público. Mandar de novo umaurlque já existe atualiza aquele webhook (200), sem criar outro.headers: até 5, enviados em toda entrega, para o seu destino autenticar. Nas respostas, o valor volta como***.- A resposta da criação (
201) traz osecretinteiro, só nela (e quando você o troca comrotate_secret): guarde-o. Na atualização pela mesmaurl(200) ele vem mascarado e o que você guardou continua valendo.
Webhook global
O dono do servidor (header admintoken) tem um webhook global, em /server/webhook,
com os mesmos campos e a mesma entrega. Ele recebe os eventos de todas as inboxes do servidor; inbox (no
envelope) diz de qual veio cada evento, e as falhas guardadas trazem a inbox em inbox_id.
O que chega
Cada evento é um POST com o envelope no corpo (Content-Type: application/json) e três headers do padrão
Standard Webhooks:
| Header | O que é |
|---|---|
Webhook-Id | O id do evento (o mesmo id do envelope). Igual nas novas tentativas: use para descartar repetidos. |
Webhook-Timestamp | Quando a entrega saiu (segundos Unix). Recuse entregas muito antigas (por exemplo, mais de 5 minutos). |
Webhook-Signature | v1, e o HMAC-SHA256, em base64, de <Webhook-Id>.<Webhook-Timestamp>.<corpo>, com a chave do secret (a parte depois de whsec_, decodificada de base64). |
Conferir a assinatura prova que a entrega saiu da Orkesio e que o corpo não mudou. O passo a passo, com exemplos em Node, Python e PHP e um caso de teste, está em Conferir a assinatura (HMAC).
Responder
Responda 2xx rápido, depois de registrar o evento, e processe à parte. O corpo da sua resposta é ignorado.
Quando a entrega falha
- Novas tentativas: com
retries(até 3), a entrega é repetida depois de 10 s, 1 min e 5 min, só quando não há risco de chegar em dobro: a conexão nem abriu, ou o destino respondeu429,502ou503. Tempo esgotado,500e504não repetem, porque o destino pode ter processado o evento. - Falhas guardadas: a entrega de
message.receivedoumessage.sentque falhou de vez fica 24 horas emGET /webhooks/{webhook_id}/failures. A falha dos outros eventos conta só emhealth. - Reenvio:
POST /webhooks/resendsreenvia as de mensagem, montadas de novo a partir da mensagem salva, com o mesmoWebhook-Id. - Desligamento: depois de 24 horas sem nenhuma resposta boa (com pelo menos 10 falhas), a API desliga o webhook e
marca
health.disabled_at. Salvar de novo (PATCH) religa. - Saúde: cada webhook traz
health, com o tempo de resposta do destino, as falhas em seguida e o último erro. - Teto de espera: cada webhook guarda até 200 novas tentativas aguardando o intervalo (10 s, 1 min, 5 min). Com o destino fora do ar e muitos eventos, o que passa disso falha de vez na hora.
- Reinício do servidor: as novas tentativas que estavam esperando se perdem e não ficam nas falhas guardadas.
Repetidos
A entrega é best effort: um evento pode se perder (resposta 500, tempo esgotado, teto de espera ou reinício, como
acima) e pode chegar duas vezes (um reenvio das falhas guardadas, ou um 502/503 devolvido por um proxy depois de o
destino já ter processado). Guarde o Webhook-Id dos últimos eventos e ignore o que já viu; para não perder dado,
confira pelas rotas de leitura o que importa.
Vindo do webhook da uazapi
O GET /webhooks também lista os webhooks da uazapi (format: "v1", eventos em
v1_events). Por aqui, eles só ligam e desligam (PATCH com enabled) e se apagam; o resto se altera no /webhook.
Para passar a receber o formato da Orkesio:
- Crie um webhook com
POST /webhookse os eventos da Orkesio. Pode ser o mesmo link do webhook da uazapi, com um caminho ou header que diga o formato. - Confira que as entregas chegam e que a assinatura bate.
- Desligue o da uazapi (
PATCHcomenabled: false) ou apague. Enquanto os dois estiverem ligados, cada evento chega duas vezes, uma em cada formato.