Pular para o conteúdo

Webhooks de eventos

Um webhook de eventos envia um POST ao seu sistema quando um fato acontece no SquadOS. Ele serve para alimentar CRM, CDP, painel interno ou automações externas sem consultar a API repetidamente.

Abra Configurações → Desenvolvedores → Webhooks. Os nomes da navegação e dos botões abaixo correspondem ao catálogo PT-BR atual.

O acesso usa capacidades granulares:

CapacidadeContrato do produto
webhooks.viewAbre a seção e permite ler os destinos e o histórico no backend
webhooks.writeCria, edita, testa, gira a chave, ativa/desativa e agenda reenvio
webhooks.deleteExclui o destino e o histórico associado

Proprietários e administradores mantêm essas permissões pelo contrato legado. Em funções personalizadas, conceda webhooks.write e webhooks.delete para gestão completa; ambas dependem de webhooks.view.

A lista mostra nome, URL, estado e até três eventos por destino. Os estados são Ativo, Desativado e Desativado por falha. Uma organização pode ter no máximo 10 webhooks.

Selecione Novo webhook e complete as quatro seções. O formulário só permite criar quando há nome, URL HTTPS, pelo menos um evento, filtros completos e cabeçalhos válidos.

Informe um nome e a URL final do receptor. A URL precisa começar com https://.

Na entrega, o SquadOS também bloqueia localhost, redes privadas ou reservadas, endpoints de metadata, o próprio projeto Supabase e hosts cujo DNS não possa ser validado. Essa checagem ocorre depois que o destino foi salvo; uma URL bloqueada encerra a entrega sem retentativa.

O catálogo atual contém 25 eventos. Marcar tudo em uma família não inclui as três notas internas, que começam desmarcadas.

Mensagens

Nome na interfaceTipo enviadoQuando ocorre
Mensagem recebidamessage.receivedUm contato envia uma mensagem
Mensagem enviadamessage.sentUm agente de IA ou pessoa da equipe responde; no streaming, somente após o texto final
Mensagem editadamessage.updatedO texto de uma mensagem muda
Mensagem apagadamessage.deletedA mensagem recebe a marca de exclusão

Conversas

Nome na interfaceTipo enviado
Conversa abertaconversation.created
Conversa atribuídaconversation.assigned
Conversa transferidaconversation.transferred
Conversa devolvida à IAconversation.transferred_to_agent
Conversa concluídaconversation.resolved
Conversa reabertaconversation.reopened
IA ligada ou desligadaconversation.ai_toggled
Conversa adiadaconversation.snoozed
Conversa retomadaconversation.unsnoozed
Contatos unificados na conversaconversation.contacts_merged
Nota interna criadaconversation.internal_note_created
Nota interna editadaconversation.internal_note_updated
Nota interna apagadaconversation.internal_note_deleted
Etiqueta na conversaconversation.tag_added
Etiqueta retirada da conversaconversation.tag_removed

Avaliação e contatos

Nome na interfaceTipo enviado
Avaliação concluídasatisfaction.completed
Contato criadocontact.created
Contato atualizadocontact.updated
Contatos unificadoscontact.merged
Etiqueta no contatocontact.tag_added
Etiqueta retirada do contatocontact.tag_removed

Sem filtro, o destino recebe todos os tipos marcados. Os critérios disponíveis são Caixa de entrada, Dono da conversa, Tag da conversa, Tag do contato, Canal e IA da conversa. Condições diferentes são combinadas com E; dentro de um critério de conjunto, os valores selecionados formam OU.

Filtros cujo eixo não existe no evento são ignorados. Por exemplo, eventos de contato não têm conversa, caixa, dono, canal nem estado da IA; um filtro nesses eixos não bloqueia contact.created. O critério Tag do contato continua aplicável.

Use Cabeçalhos adicionais quando o receptor exigir, por exemplo, Authorization: Bearer .... Content-Type e qualquer nome iniciado por X-Squados- são reservados e não podem ser sobrescritos.

O controle Ativo funciona ao editar um destino existente. Na criação atual, o webhook é gravado ativo mesmo se o controle estiver desligado. Se ele precisar começar pausado, crie-o e desative-o imediatamente na lista.

Depois de criar, copie a Chave de verificação: ela aparece uma única vez. Gerar nova chave na edição invalida a anterior imediatamente; entregas seguintes usam a nova chave, enquanto uma requisição já assinada pode falhar e voltar pela retentativa.

Ainda no painel da chave, Enviar evento de teste envia dados fictícios pelo mesmo guard, assinatura e sender das entregas reais. Na edição, o mesmo botão usa o primeiro tipo marcado. O payload contém data.test: true, aparece no histórico e mostra o status, a duração e o começo da resposta do receptor.

Toda entrega usa este envelope:

{
"id": "9f2c1b7e-3a44-4d1c-9b0e-52a7c8e1d004",
"type": "message.received",
"api_version": "2026-08-24",
"occurred_at": "2026-09-02T14:03:11.482Z",
"organization_id": "6d1b0a52-8f3e-4c77-9a10-2b5e7c9d3311",
"data": {
"message": {
"id": "8f2b1c4e-0000-4000-8000-000000000001",
"role": "user",
"sender_kind": "contact",
"content": "Olá",
"attachments": [],
"created_at": "2026-09-02T14:03:11.400Z"
},
"conversation": {
"id": "a41d9e77-0000-4000-8000-000000000001",
"status": "open",
"ai_enabled": true,
"channel_type": "whatsapp_official",
"channel_family": "whatsapp",
"inbox": { "id": "00000000-0000-4000-8000-0000000010b0", "name": "Comercial" },
"agent": { "id": "00000000-0000-4000-8000-000000000a6e", "name": "Recepcionista" },
"assigned_to": null
},
"contact": {
"id": "c7e30b12-0000-4000-8000-000000000001",
"display_name": "João Ribeiro",
"identity_type": "whatsapp",
"identity_value": "+5511988887777"
}
}
}

data varia por família:

FamíliaBlocos principais
Mensagemmessage, conversation, contact; mensagens do assistente também incluem modelo, tokens, créditos e custo quando disponíveis
Conversaconversation, contact, actor, event; mudanças de etiqueta também incluem tag
Avaliaçãosatisfaction, conversation, contact
Contatocontact; mudanças de etiqueta incluem tag, e unificação inclui o contato de destino

Esses blocos são resumos curados do estado no momento do fato, não cópias completas das linhas internas. Campos novos podem aparecer na mesma api_version; ignore chaves desconhecidas. Use occurred_at para ordenar e o id do envelope para deduplicar.

CabeçalhoConteúdo
X-Squados-EventTipo do evento
X-Squados-DeliveryID da entrega; permanece igual nas retentativas automáticas e muda em um reenvio manual
X-Squados-TimestampMomento da tentativa, em segundos Unix
X-Squados-SignatureHMAC no formato sha256=<hexadecimal>

A assinatura é HMAC-SHA256(chave, "<timestamp>.<corpo cru>"). Confira a assinatura com comparação constante, rejeite timestamps antigos conforme a janela de segurança da sua integração e só depois processe o JSON.

import crypto from "node:crypto";
function assinaturaConfere(chave, timestamp, corpoCru, recebida) {
const esperada =
"sha256=" +
crypto.createHmac("sha256", chave).update(`${timestamp}.${corpoCru}`).digest("hex");
const a = Buffer.from(esperada);
const b = Buffer.from(recebida ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}

A fila é consultada uma vez por minuto. Uma resposta 2xx conclui a entrega. 3xx, 4xx, 5xx, conexão recusada e timeout de 15 segundos falham; redirects não são seguidos. O histórico guarda até 4.000 caracteres do corpo da resposta e até 1.000 do erro.

O runtime atual faz no máximo seis tentativas:

TentativaEspera depois da falha anterior
Próximo ciclo da fila
1 minuto
5 minutos
15 minutos
1 hora
6ª e terminal3 horas

Assim, uma entrega que falha sempre se torna terminal em aproximadamente 4h21, além do tempo dos ciclos da fila. Uma URL bloqueada pelo guard ou um webhook sem chave morre na primeira tentativa, pois repetir não mudaria o resultado.

A garantia é pelo menos uma vez: uma resposta perdida ou lease recuperado pode repetir o mesmo evento, e a ordem entre eventos não é garantida. Deduplicate pelo id do envelope, não pelo X-Squados-Delivery.

Depois de cinco entregas terminais consecutivas para o mesmo problema e URL, o destino é marcado Desativado por falha. Proprietários e administradores recebem o alerta por e-mail. Corrija o receptor e use Ativar; a reativação zera os contadores e resolve o alerta aberto.

Abra Histórico de entregas no destino. A lista pagina 25 itens por vez e mostra tipo, estado, HTTP, duração, número de tentativas, payload enviado, resposta recebida e marcações de teste ou reenvio.

Entregas dead — e registros legados failed — oferecem Reenviar. O comando cria uma nova entrega pendente ligada à original, mesmo se o destino estiver desativado. Ele não apaga nem modifica a falha anterior e sai no próximo ciclo da fila.

Eventos e entregas são apagados depois de 30 dias. Excluir o webhook também apaga imediatamente seu segredo e histórico. Eventos ocorridos enquanto o destino está desativado não são acumulados.

  1. Responda 2xx rapidamente e processe trabalho pesado fora da requisição.
  2. Valide X-Squados-Timestamp e X-Squados-Signature contra o corpo cru.
  3. Deduplicate pelo id do envelope.
  4. Ignore campos desconhecidos e trate blocos opcionais ou null.
  5. Monitore falhas e use o histórico antes que o destino seja desativado.
  6. Para recuperar estado atual ou dados fora da retenção, consulte a API REST.