Eventos do webhook
O formato exato do que chega no seu sistema, com exemplos reais.
Nesta página
Cada aviso chega no envelope descrito em Webhooks. Aqui está o data de cada evento, com exemplos gerados pelo próprio NextChat e o significado de cada campo.
Regras que valem para todos:
- Datas em ISO 8601 (com fuso, por exemplo
2026-10-23T10:05:12-03:00ou…Z). - Ids são UUIDs, exceto
external_id(o id do WhatsApp). - Telefones só com dígitos e código do país (
5511988887777). - Campo sem valor vem
null(objetos e ids) ou""(textos); listas vazias vêm[]. - Podem aparecer campos novos a qualquer momento. Ignore o que não conhece.
message.received e message.sent
message.received sai quando o cliente escreve. message.sent sai quando uma mensagem é enviada para o cliente: pelo app, pelo celular, pela API ou por automação. O data é o mesmo nos dois.
{
"id": "6f1d0a8e-3b5c-4c1e-9d2a-7e8f9a0b1c2d",
"type": "message.received",
"created_at": "2026-10-23T13:05:11.0620109Z",
"tenant_id": "aba0b704-72e3-41aa-9832-244c62f4c2f8",
"data": {
"id": "ad4706de-b1cf-43fe-9aab-7be6f5e53dfc",
"conversation_id": "f5fc0812-8dae-44b3-ac74-5d46bbaa7c4d",
"channel_id": "be34f999-8373-4c88-95c3-9821d5a97181",
"contact": { "id": "8103a781-4297-4408-b16c-92827738c56d", "name": "Maria Souza", "phone": "5511988887777", "group": false },
"channel": { "id": "be34f999-8373-4c88-95c3-9821d5a97181", "name": "Delivery", "phone": "5511999990000" },
"external_id": "3EB0C431D5A2F8B6E1",
"direction": "in",
"origin": "phone",
"type": "text",
"body": "Quero 2 pizzas grandes",
"reply_to_external_id": "",
"status": "sent",
"error": null,
"sent_at": "2026-10-23T10:05:11.01424-03:00",
"created_at": "2026-10-23T10:05:11.027563-03:00",
"edited_at": null,
"media_id": null,
"media": null,
"media_error": null,
"sender_user_id": null,
"sender_name": null,
"client_id": null,
"group_sender": null,
"owner_at_send": null,
"reactions": [],
"starred": false,
"forwarded": false,
"hidden": false
}
}{
"id": "6ad78585-8b83-46e9-a37c-edf2a4c00975",
"type": "message.received",
"created_at": "2026-10-23T13:05:13.7386493Z",
"tenant_id": "aba0b704-72e3-41aa-9832-244c62f4c2f8",
"data": {
"id": "3b3e650d-43a6-4661-b90b-db8f83a2b2bd",
"conversation_id": "f5fc0812-8dae-44b3-ac74-5d46bbaa7c4d",
"channel_id": "be34f999-8373-4c88-95c3-9821d5a97181",
"contact": { "id": "8103a781-4297-4408-b16c-92827738c56d", "name": "Maria Souza", "phone": "5511988887777", "group": false },
"channel": { "id": "be34f999-8373-4c88-95c3-9821d5a97181", "name": "Delivery", "phone": "5511999990000" },
"external_id": "3EB0D5F1A9C27E4B80",
"direction": "in",
"origin": "phone",
"type": "image",
"body": "a de cima",
"reply_to_external_id": "",
"status": "sent",
"error": null,
"sent_at": "2026-10-23T10:05:13.000427-03:00",
"created_at": "2026-10-23T10:05:13.005339-03:00",
"edited_at": null,
"media_id": "d09bb41d-e84b-4949-a8e9-b369d92d55a2",
"media": {
"id": "d09bb41d-e84b-4949-a8e9-b369d92d55a2",
"kind": "image",
"mime_type": "image/jpeg",
"file_name": "foto.jpg",
"size_bytes": 81234,
"duration_ms": 0,
"voice": false,
"gif": false,
"url": "https://…link assinado, vale 15 minutos…"
},
"media_error": null,
"sender_user_id": null,
"sender_name": null,
"client_id": null,
"group_sender": null,
"owner_at_send": null,
"reactions": [],
"starred": false,
"forwarded": false,
"hidden": false
}
}{
"id": "4b22796d-93f4-41fa-819c-5164e685e9fe",
"type": "message.sent",
"created_at": "2026-10-23T13:05:55.6493291Z",
"tenant_id": "aba0b704-72e3-41aa-9832-244c62f4c2f8",
"data": {
"id": "c1caa163-ed84-409e-9e19-d967795e0fe0",
"conversation_id": "f5fc0812-8dae-44b3-ac74-5d46bbaa7c4d",
"channel_id": "be34f999-8373-4c88-95c3-9821d5a97181",
"contact": { "id": "8103a781-4297-4408-b16c-92827738c56d", "name": "Maria Souza", "phone": "5511988887777", "group": false },
"channel": { "id": "be34f999-8373-4c88-95c3-9821d5a97181", "name": "Delivery", "phone": "5511999990000" },
"external_id": "3B60CCF65A3F4BA797632554BC3C9F4B",
"direction": "out",
"origin": "app",
"type": "text",
"body": "Anotado! Já já sai.",
"reply_to_external_id": "",
"status": "pending",
"error": null,
"sent_at": "2026-10-23T10:05:55.644456-03:00",
"created_at": "2026-10-23T10:05:55.644905-03:00",
"edited_at": null,
"media_id": null,
"media": null,
"media_error": null,
"sender_user_id": "70cf7396-3873-48c0-b2c5-be78dc938397",
"sender_name": "Amanda",
"client_id": "3b60ccf6-5a3f-4ba7-9763-2554bc3c9f4b",
"group_sender": null,
"owner_at_send": null,
"reactions": [],
"starred": false,
"forwarded": false,
"hidden": false
}
}Campos da mensagem
| Campo | Tipo | O que é |
|---|---|---|
id | uuid | Id da mensagem no NextChat. Use para não importar a mesma mensagem duas vezes |
conversation_id | uuid | A conversa. Para responder: POST /conversations/{conversation_id}/messages |
channel_id | uuid | O número de WhatsApp da empresa (igual a channel.id) |
contact | objeto | Quem é o cliente: id, name, phone, group (veja abaixo) |
channel | objeto | O número da empresa: id, name (como está no NextChat), phone |
external_id | texto | Id da mensagem no WhatsApp |
direction | in · out | in = o cliente escreveu; out = saiu para o cliente |
origin | texto | De onde veio: phone (do WhatsApp: o cliente, ou a equipe pelo celular), app (pelo NextChat ou pela API), automation (automação ou menu), history (importada do histórico), system (aviso de grupo) |
type | texto | text, image, audio, video, document, sticker, location, contact, poll, system |
body | texto | O texto, ou a legenda do arquivo ("" sem legenda). Em location, contact e poll, uma descrição em texto |
reply_to_external_id | texto | external_id da mensagem que esta responde ("" se não for resposta) |
status | texto | pending (saindo), sent, delivered, read, failed. Em message.sent costuma vir pending: o aviso sai quando a mensagem é criada |
error | objeto · null | Só em failed: code, message, at, attempts |
sent_at | data | Quando a mensagem foi enviada no WhatsApp. Use para ordenar |
created_at | data | Quando o NextChat registrou a mensagem |
edited_at | data · null | Quando foi editada |
media_id | uuid · null | O arquivo (igual a media.id). null sem arquivo |
media | objeto · null | O arquivo: veja abaixo |
media_error | texto · null | Só quando o arquivo não pôde ser baixado: evicted (expirou no WhatsApp) ou o motivo |
sender_user_id | uuid · null | Quem da equipe enviou pelo app (null para o cliente, o celular e automações) |
sender_name | texto · null | Nome de quem enviou (assinatura da pessoa) |
client_id | texto · null | O id que o app ou a API usou ao enviar (idempotência). null em recebidas |
group_sender | texto · null | Em grupos: o nome de quem escreveu |
owner_at_send | uuid · null | A mensagem foi enviada no atendimento de outra pessoa (o responsável na hora) |
reactions | lista | Reações: reactor, emoji, sender_user_id |
starred · forwarded · hidden | sim/não | Favoritada, encaminhada, apagada só para a equipe |
Campos que aparecem só em alguns tipos:
| Campo | Quando |
|---|---|
view_once | Mensagem de visualização única (chega sem arquivo nem legenda) |
contact_card · contact_cards | type: "contact": o cartão de contato compartilhado (e a lista, se forem vários) |
location | type: "location": latitude, longitude, nome e endereço |
poll | type: "poll": a pergunta e as opções |
interactive | Mensagem com botões ou lista (de empresas e robôs) |
choice | Resposta do cliente a um botão ou lista (body = o que ele escolheu) |
group_sender_jid | Em grupos: o identificador de quem escreveu |
O arquivo (media)
| Campo | O que é |
|---|---|
id | Id do arquivo. Link novo: GET /media/{id}/url |
kind | image, audio, video, document, sticker |
mime_type | Por exemplo image/jpeg, audio/ogg, application/pdf |
file_name | Nome do arquivo (pode vir vazio em fotos e áudios) |
size_bytes | Tamanho em bytes |
duration_ms | Áudio e vídeo: duração em milissegundos |
voice | true em áudio gravado no WhatsApp (mensagem de voz) |
gif | true em vídeo que toca como GIF |
url | Link assinado para baixar sem chave. Vale 15 minutos a partir do evento |
O aviso de mensagem com arquivo só sai quando o arquivo está pronto. Detalhes em Mensagens com arquivo.
O contato e o número
| Campo | O que é |
|---|---|
contact.id | Id do contato no NextChat |
contact.name | Nome salvo pela equipe, ou da agenda, ou do perfil do WhatsApp, ou o telefone |
contact.phone | Telefone do cliente, só dígitos (5511988887777) |
contact.group | true em grupos (aí name é o nome do grupo e quem escreveu vem em group_sender) |
channel.id · channel.name · channel.phone | O número de WhatsApp da empresa que recebeu ou enviou |
conversation.updated
Sai sempre que algo na conversa muda: chegou ou saiu mensagem, mudou o responsável, o setor, as etiquetas, foi lida, arquivada… É o evento mais frequente: assine só se precisar acompanhar o estado da conversa.
{
"id": "13b635cd-f200-402b-921a-e27a41984aa9",
"type": "conversation.updated",
"created_at": "2026-10-23T13:05:11.073012Z",
"tenant_id": "aba0b704-72e3-41aa-9832-244c62f4c2f8",
"data": {
"id": "f5fc0812-8dae-44b3-ac74-5d46bbaa7c4d",
"channel_id": "be34f999-8373-4c88-95c3-9821d5a97181",
"contact_id": "8103a781-4297-4408-b16c-92827738c56d",
"name": "Maria Souza",
"push_name": "Maria",
"phone": "5511988887777",
"lid": "",
"is_group": false,
"label_ids": [],
"assignee_id": null,
"assignee_name": "",
"sector": null,
"sector_assigned_at": null,
"attendance": { "id": "77bf7e70-2f23-4483-9602-9b6dabb3cff6", "protocol": 1, "opened_at": "2026-10-23T10:05:11.044073-03:00", "opened_by": "customer" },
"unread_count": 1,
"last_message_id": "ad4706de-b1cf-43fe-9aab-7be6f5e53dfc",
"last_message_at": "2026-10-23T10:05:11.01424-03:00",
"last_message_preview": "Quero 2 pizzas grandes",
"last_message_direction": "in",
"last_message_status": "sent",
"waiting_cleared_at": null,
"pinned": false,
"muted": false,
"archived": false,
"blocked": false,
"pinned_message": null,
"menu": null,
"ai": null,
"avatar_url": "",
"avatar_media_id": null,
"updated_at": "2026-10-23T10:05:11.027563-03:00"
}
}| Campo | O que é |
|---|---|
id | A conversa |
channel_id · contact_id | O número da empresa e o contato |
name · push_name · phone | Nome mostrado, nome do perfil do WhatsApp e telefone |
is_group | Conversa de grupo |
label_ids | Etiquetas da conversa (nomes em GET /labels) |
assignee_id · assignee_name | Responsável pela conversa (null = ninguém) |
sector | Setor: {id, name, color} ou null |
attendance | Atendimento aberto: {id, protocol, opened_at, opened_by} ou null |
unread_count | Mensagens não lidas pela equipe |
last_message_* | A última mensagem: id, data, prévia do texto, direção e status |
waiting_cleared_at | Quando a espera foi zerada sem atendimento |
pinned · muted · archived · blocked | Fixada, silenciada, arquivada, bloqueada |
menu | Menu de opções em andamento: {state, step} ou null |
ai | A IA está com a conversa: {since, by_name} ou null |
attendance.opened e attendance.closed
O atendimento é o protocolo: abre quando o cliente escreve (ou a equipe inicia) e fecha quando alguém finaliza.
{
"id": "0976c9b6-573c-41d2-aada-fc9a8b60b8d5",
"type": "attendance.closed",
"created_at": "2026-10-23T13:20:57.6741519Z",
"tenant_id": "aba0b704-72e3-41aa-9832-244c62f4c2f8",
"data": {
"id": "77bf7e70-2f23-4483-9602-9b6dabb3cff6",
"protocol": 1,
"protocol_label": "NC-000001",
"status": "closed",
"conversation_id": "f5fc0812-8dae-44b3-ac74-5d46bbaa7c4d",
"channel_id": "be34f999-8373-4c88-95c3-9821d5a97181",
"contact_name": "Maria Souza",
"contact_phone": "5511988887777",
"opened_by": "customer",
"opened_at": "2026-10-23T10:05:11.044073-03:00",
"first_response_at": "2026-10-23T10:05:55.644905-03:00",
"first_response_by": "70cf7396-3873-48c0-b2c5-be78dc938397",
"assignee_id": null,
"assignee_name": "",
"sector_id": null,
"closed_at": "2026-10-23T10:20:57.664268-03:00",
"close_reason": ""
}
}| Campo | O que é |
|---|---|
id · protocol · protocol_label | O atendimento, o número e o protocolo formatado |
status | open ou closed |
conversation_id · channel_id | A conversa e o número da empresa |
contact_name · contact_phone | O cliente |
opened_by | Quem abriu: customer (o cliente escreveu), team, menu ou api |
opened_at · closed_at | Abertura e fechamento (closed_at é null no opened) |
first_response_at · first_response_by | A primeira resposta da equipe e quem respondeu |
assignee_id · assignee_name · sector_id | Responsável e setor |
close_reason | O motivo escrito ao finalizar, ou o automático (por exemplo “sem retorno há 7 dias”) |
kanban.card.created, kanban.card.moved e kanban.card.completed
Os cartões saem só com os campos públicos: sem contato, mensagens nem valores. Cartões privados nunca saem. kanban.card.completed sai junto com o moved quando o cartão vai para uma etapa de ganho.
{
"id": "a2c4e6f8-1357-4b9d-8e0f-2468ace13579",
"type": "kanban.card.moved",
"created_at": "2026-10-23T14:00:00Z",
"tenant_id": "aba0b704-72e3-41aa-9832-244c62f4c2f8",
"data": {
"from_stage_id": "1a2b3c4d-0000-4000-8000-000000000001",
"to_stage_id": "1a2b3c4d-0000-4000-8000-000000000002",
"actor_id": "70cf7396-3873-48c0-b2c5-be78dc938397",
"card": {
"id": "9e8d7c6b-5a49-4382-9170-8f6e5d4c3b2a",
"board_id": "0b1c2d3e-4f50-4617-8293-a4b5c6d7e8f9",
"board_name": "Pedidos",
"stage_id": "1a2b3c4d-0000-4000-8000-000000000002",
"stage_name": "Em preparo",
"stage_kind": "open",
"title": "Pedido da Maria",
"description": "2 pizzas grandes",
"priority": "high",
"due_at": "2026-10-23T21:00:00Z",
"labels": [{ "id": "…", "name": "Delivery", "color": "#dbeafe", "text_color": "#1e40af" }],
"assignee_id": "70cf7396-3873-48c0-b2c5-be78dc938397",
"assignee_name": "Amanda",
"checklist_total": 3,
"checklist_done": 1,
"archived": false,
"closed_at": null,
"version": 4,
"created_at": "2026-10-23T13:10:00Z",
"updated_at": "2026-10-23T14:00:00Z"
}
}
}| Campo | O que é |
|---|---|
from_stage_id · to_stage_id | Só em moved/completed: de qual etapa para qual |
actor_id | Só em moved/completed: quem moveu |
card | No created, data tem só card |
card.stage_kind | open, won (ganho: gera o completed) ou lost |
card.priority | low, medium, high, urgent |
card.version | Versão do cartão (sobe a cada mudança) |
card.labels | Etiquetas do cartão: id, name, color, text_color |
Para ler o cartão completo (campos personalizados, checklist, comentários), use GET /kanban/cards/{id}.
webhook.test
Enviado só pelo botão Testar ou por POST /integrations/webhooks/{id}/test. Não entra na fila nem no histórico.
{
"id": "0f6c2a1e-…",
"type": "webhook.test",
"created_at": "2026-10-23T13:00:00Z",
"tenant_id": "aba0b704-72e3-41aa-9832-244c62f4c2f8",
"data": { "message": "Teste de webhook do NextChat" }
}