Pular para o conteúdo principal

Webhooks do CRM

Webhook é o caminho de volta: o Workfuse faz um POST assinado para a sua URL quando algo muda aqui. É assim que você descobre o resultado do que enviou de forma assíncrona. Para o lote, também dá para consultar o resultado.

Prévia — contrato em discussão (17/09/2026)

O mecanismo de webhook já existe e está em produção (configuração, envelope, assinatura, retry). contact.created e contact.updated já são emitidos. O que continua prévia é event.received, que ainda não é emitido.

O mecanismo — como registrar a URL, validar a assinatura HMAC e tratar a entrega — é o mesmo de todos os módulos e está em Webhooks. Esta página traz só o que o CRM emite.

EventoQuando dispara
contact.createdUm contato foi criado pela API, pelo lote ou por evento (política CREATE_CONTACT).
contact.updatedUma propriedade de contato mudou pela API, pelo lote ou por evento.
event.receivedUm evento enviado por você terminou de ser processado. Ainda não é emitido.

Só as vias de integração emitem. Contato criado ou alterado no painel, em formulário, no chat, na inscrição, pelo ERP ou por vínculo de usuário não dispara nada.

Ao registrar o webhook, você assina os que interessam — ou nenhum, e recebe todos.

contact.created​

{
"id": "evt_01J8ZQ9M2P",
"event": "contact.created",
"data": {
"contactId": "clz9q2k8r0001s6vp2h4m7x1e",
"externalId": "aluno-4471",
"origin": "API",
"createdAt": "2026-09-17T13:02:11.482Z"
}
}

origin diz de onde veio: API (criação direta), BATCH (lote) ou EVENT (política CREATE_CONTACT de uma definição).

Um evento que cria o contato e traz contact.properties gera dois webhooks: contact.created e, em seguida, contact.updated com as chaves gravadas.

contact.updated​

{
"id": "evt_01J8ZQ9M2Q",
"event": "contact.updated",
"data": {
"contactId": "clz9q2k8r0001s6vp2h4m7x1e",
"externalId": "aluno-4471",
"changedProperties": ["phone", "interesse_em_bolsa"],
"origin": "BATCH",
"updatedAt": "2026-09-17T13:07:44.201Z"
}
}

changedProperties lista só as chaves que mudaram de valor, nativas (email, phone, …) e customizadas. Gravar o mesmo valor de novo não dispara o evento — o que importa é a mudança, não a escrita.

O payload não carrega os valores, só as chaves. Para ler o valor novo, chame GET /crm/contacts/{contactId}. É de propósito: propriedade de contato pode conter dado pessoal, e a URL de webhook é configuração do cliente.

event.received​

O desfecho do que você mandou em POST /crm/events:

{
"id": "evt_01J8ZQ9M2R",
"event": "event.received",
"data": {
"eventId": "clzd8p3r40004s6vp6c2n5t7b",
"deliveryId": "insc-2026-88431",
"eventName": "inscricao_concluida",
"contactResolution": "RESOLVED_EXTERNAL_ID",
"contactId": "clz9q2k8r0001s6vp2h4m7x1e",
"dealId": "clzc4n7p20003s6vp1f5j8w3a",
"appliedProperties": {
"contact": ["origem_do_lead"],
"deal": ["curso_de_interesse"]
},
"offSchemaKeys": ["valor_da_taxa"],
"rejectionReason": null
}
}
CampoO que é
deliveryIdO seu id. É por ele que você correlaciona com o que enviou.
contactResolutionComo o contato foi achado — a tabela está em Eventos.
contactIdnull quando não resolveu.
dealIdO Negócio que recebeu propriedade, ou null.
appliedPropertiesO que foi gravado de fato, por objeto.
offSchemaKeysChaves que você mandou e a definição não declara.
rejectionReasonPreenchido só quando contactResolution é REJECTED_UNKNOWN_CONTACT.

Dispara também quando o evento foi recusado — com rejectionReason explicando. Recusa que não avisa é indistinguível de entrega que nunca chegou.

Três coisas para acertar no receiver​

  • Correlacione por deliveryId, não por eventId. O deliveryId é o seu; o eventId é nosso.
  • A entrega é at-least-once e pode repetir. O id do envelope (evt_…) é o mesmo em todas as tentativas: use-o como chave de deduplicação e responda 2xx rápido, processando de forma assíncrona do seu lado. Sem 2xx, tentamos de novo por cerca de 3h45 (10 tentativas).
  • Não presuma ordem. contact.created e contact.updated do mesmo contato podem chegar fora de ordem.

Cuidado com o laço​

contact.updated dispara para mudança feita pelas vias de integração — inclusive a que a sua própria integração acabou de fazer. Um receiver que reage a contact.updated escrevendo de volta no contato fecha um laço infinito.

Filtre por origin, ou compare changedProperties com o que você acabou de enviar, antes de escrever de volta.