Receber webhooks
Cadastre o endereço na aba Webhooks ou pela rota Criar webhook. Para cada evento, enviamos um POST com o JSON abaixo. Responda com qualquer status 2xx em até 10 s. Sem 2xx, tentamos de novo depois de 30 s, 2 min, 10 min, 30 min, 2 h e 6 h; depois disso a entrega fica como falha e pode ser reenviada pelo painel ou pela API.
Cabeçalhos
| Cabeçalho | Conteúdo |
|---|---|
X-Clint-Event | Tipo do evento, ex. ligacao.finalizada. |
X-Clint-Delivery | Id desta entrega. Muda a cada reenvio manual. |
X-Clint-Timestamp | Momento do envio, em segundos (Unix). |
X-Clint-Signature | sha256= + HMAC-SHA256 do texto {timestamp}.{corpo} com o segredo do webhook. |
Eventos
| Evento | Quando |
|---|---|
lead.recebido | O lead entrou na fila do discador, por qualquer origem. |
ligacao.finalizada | Uma tentativa de ligação terminou. Traz o resultado, a duração e o número da tentativa. |
lead.tabulado | A ligação recebeu uma tabulação. |
lead.finalizado | O lead foi encerrado e não será mais discado. Traz a tabulação final e o total de tentativas. |
lead.removido | O lead foi removido pelo painel ou pela API. |
discador.ligado / discador.parado | O discador começou ou parou de ligar, inclusive na parada automática da noite. |
teste | Enviado pelo botão Enviar teste. |
O id do evento é fixo para o mesmo registro (ex. evt_call_344 para a ligação 344). Se receber o mesmo id duas vezes, ignore a repetição. Os eventos chegam em até 1 minuto depois de acontecerem.
Exemplo: ligacao.finalizada
{
"id": "evt_call_344",
"type": "ligacao.finalizada",
"createdAt": "2026-11-10T14:53:40+00:00",
"data": {
"idLigacao": 344,
"nrLead": 117,
"codCliente": "f746f727-e1fd-41dc-abc4-9975fc5d4feb",
"nome": "JEFERSON",
"telefone": "73998493569",
"dataHora": "2026-11-10T11:53:21.000-03:00",
"resultado": "NÃO COMPLETADA",
"resultadoGrupo": "sem_resposta",
"atendida": false,
"duracaoSegundos": 20,
"tentativa": 3
}
}
resultadoGrupo: atendida, sem_resposta, caixa_postal, cancelada, numero_invalido ou outra.
Exemplo: lead.finalizado
{
"id": "evt_fin_659",
"type": "lead.finalizado",
"createdAt": "2026-11-10T14:48:40+00:00",
"data": {
"nrLead": 286,
"codCliente": "ed1545b4-6e56-46bd-ae0d-088f2b62b45e",
"nome": "RAISSA",
"dataHora": "2026-11-10T11:48:33.000-03:00",
"tabulacao": "CONTRATO FECHADO",
"categoria": "SUCESSO",
"tipo": "FINALIZADO",
"historico": null,
"tentativas": 2
}
}
Conferir a assinatura (Python)
import hmac, hashlib
def assinatura_valida(segredo: str, timestamp: str, corpo: bytes, assinatura: str) -> bool:
esperado = "sha256=" + hmac.new(segredo.encode(), timestamp.encode() + b"." + corpo, hashlib.sha256).hexdigest()
return hmac.compare_digest(esperado, assinatura)
Conferir a assinatura (Node.js)
const crypto = require("crypto");
function assinaturaValida(segredo, timestamp, corpoBruto, assinatura) {
const esperado = "sha256=" + crypto.createHmac("sha256", segredo).update(`${timestamp}.${corpoBruto}`).digest("hex");
return esperado.length === assinatura.length && crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(assinatura));
}
Use o corpo exatamente como chegou, antes de converter para JSON. Recuse pedidos com timestamp de mais de 5 minutos atrás.