Usando o CertivantLive ID e desenvolvedorWebhooks

Webhooks

Receba eventos do Certivant em tempo real nos seus próprios sistemas quando as verificações mudarem de status, com configuração, validação de assinatura HMAC, cronograma de novas tentativas e referência completa dos tipos de evento.

Who can do this:Org ownerOrg admin— Os membros precisam da permissão api.webhooks para visualizar; a configuração exige um administrador.

A página de Eventos de webhook mostrando o histórico de entregas de webhooks de saída: tipo de evento, URL de destino, status da entrega, tentativas, código de resposta e horário.

O que ela faz

Um webhook é uma URL para a qual enviamos um POST sempre que algo acontece na sua organização do Certivant. Em vez de consultar a nossa API em busca de mudanças ("a verificação já terminou?"), você nos informa uma URL e avisamos no instante em que isso acontecer. Os eventos de webhook são a forma de manter os seus próprios sistemas sincronizados: fluxos de onboarding de clientes, bases de risco de AML, tags de CRM, painéis internos de conformidade.

Onde encontrar

KYC → Webhooks na barra lateral esquerda. (Os eventos de KYB são enviados para os mesmos endpoints de webhook; não há uma configuração de webhook separada para KYB.)

Configuração

Escolha uma URL do seu lado

O seu endpoint deve:

  • Aceitar POSTs HTTPS com Content-Type: application/json.
  • Responder 2xx rapidamente (em menos de 5 segundos) para confirmar o recebimento.
  • Validar o cabeçalho de assinatura (próxima etapa) antes de confiar no payload.

Adicione a URL no Certivant

KYC → Webhooks → Adicionar endpoint. Um campo é aberto no próprio lugar: cole a URL e clique em Salvar (a mesma URL pode ser editada depois em Configurações → KYC/B). O cartão Endpoints de webhook mostra o endpoint padrão de toda a organização, os endpoints por formulário e o segredo de assinatura.

O cartão Endpoints de webhook: o endpoint padrão da organização com seu link Adicionar endpoint, os endpoints por formulário e o segredo de assinatura com o botão Rotacionar segredo.

Copie o segredo de assinatura

Depois de salvar, você verá um segredo de assinatura exibido uma única vez. Copie-o agora: ele não é mostrado de novo. Se você o perder, precisará rotacionar para um novo.

Valide as assinaturas do seu lado

Toda requisição tem um cabeçalho X-Certivant-Signature-V2 no formato t=<unix time>,v1=<hex>. O valor v1 é o HMAC-SHA256 do horário unix, um ponto e o corpo bruto da requisição, assinado com o segredo que você acabou de copiar. Valide-o e rejeite os eventos cujo horário esteja a mais de cinco minutos do seu próprio relógio, antes de fazer o parsing. A receita, com código em várias linguagens, está no guia do desenvolvedor.

O antigo cabeçalho X-KYC-Signature-Legacy, que assinava só o corpo, não é mais enviado (foi removido em 24 de outubro de 2026). Se o seu receptor ainda o verifica, todos os eventos agora falham na validação: passe a usar X-Certivant-Signature-V2.

Pseudocódigo:

const sig = req.headers["x-certivant-signature"];
const expected = hmac("sha256", secret).update(rawBody).digest("hex");
if (!timingSafeEqual(sig, expected)) return 401;

Não pule esta etapa. Sem a validação da assinatura, qualquer pessoa que adivinhe a URL do seu endpoint pode enviar eventos falsos para você.

Teste pelo painel

Na página Desenvolvedor, abra a seção Eventos de webhook. Escolha um evento na lista Evento de teste (kyc.webhook.test (o padrão), kyc.request.created, kyc.request.approved, kyc.request.rejected ou kyc.request.escalated) e clique em Enviar um evento de teste. O Certivant envia um evento sintético para o seu endpoint, assinado exatamente como um evento real (X-Certivant-Signature-V2, usando o seu segredo de webhook) e com test: true para que você possa diferenciá-lo. Confirme que o seu endpoint responde com um 2xx.

A seção Eventos de webhook da página Desenvolvedor: a lista de tipos de evento com uma descrição de uma linha, a lista Evento de teste e o botão Enviar um evento de teste.

Tipos de evento

EventoQuando
kyc.request.createdAlguém criou uma solicitação de verificação (painel, API ou formulário público).
kyc.request.documents_readyO solicitante enviou todos os documentos exigidos; o processamento começou.
kyc.request.approvedO status final é APPROVED (automático ou manual).
kyc.request.rejectedO status final é REJECTED.
kyc.request.escalatedEncaminhada para revisão manual.
kyc.request.cancelledUm revisor cancelou a solicitação antes da conclusão.
kyb.*Mesmo formato de kyc.*, mas para verificações de empresas.
monitoring.alert.createdUm novo alerta de monitoramento foi disparado para um solicitante aprovado anteriormente.
monitoring.alert.resolvedUm revisor resolveu um alerta.
form.submittedUm envio de formulário público. Útil quando você usa o formulário para coletar dados que não são de KYC.
webhook.testO evento de teste sintético do botão Testar. É sempre enviado, independentemente das assinaturas.

A lista completa e os payloads JSON estão documentados em KYC → Desenvolvedor → Eventos de webhook.

Formato do payload

Todo evento tem o mesmo envelope:

{
  "id": "evt_2k3f9a...",
  "type": "kyc.request.approved",
  "createdAt": "2026-05-27T14:30:00Z",
  "organizationId": "org_abc123",
  "data": { /* event-specific payload */ }
}

O campo data varia conforme o tipo de evento. Por exemplo, kyc.request.approved envia:

{
  "request": { "id": "kyr_...", "status": "APPROVED", "type": "INDIVIDUAL", ... },
  "applicant": { "id": "ka_...", "fullName": "Jane Doe", "email": "...", ... },
  "decision": { "by": "auto" | "manual", "reviewerId": "user_..." | null, "note": "..." | null },
  "policy": {
    "id": "pol_..." | null,
    "name": "default-kyc-policy",
    "version": 3 | null,
    "isDefault": true,
    "decision": "approve" | "reject" | "escalate" | "live_verification",
    "rulesFired": ["tier1-disqualified", "approve-by-score"],
    "reason": "High-risk country",
    "liveVerificationRequired": true
  }
}

O bloco policy (em kyc.request.approved / rejected / escalated) informa qual política de risco decidiu a solicitação e quais regras foram acionadas. isDefault: true significa que a política padrão do Certivant foi executada (id/version são a linha da política padrão da sua organização, ou null quando ela ainda não foi criada); uma política personalizada informa o id, o name e a version armazenados. rulesFired lista os ids das regras que corresponderam, na ordem de avaliação: use-os para ramificar a sua automação posterior. reason é o motivo da regra vencedora, quando ela definiu um. decision: "live_verification" (com liveVerificationRequired: true, em kyc.request.escalated) significa que a política quer uma verificação de identidade ao vivo antes da decisão final: a solicitação aguarda na revisão manual até que a chamada decida. Veja Criar uma política de risco.

Se você opera no modo parceiro (uma organização atendendo vários clientes finais), todo envelope de evento também traz subTenantName e subTenantExternalId, as tags definidas na solicitação quando ela foi criada pela API, para que o seu handler encaminhe o resultado ao cliente final correto. Veja a referência de webhooks para desenvolvedores para a posição exata dos campos.

Novas tentativas

Se o seu endpoint retornar um status diferente de 2xx (ou der timeout), tentamos de novo com backoff exponencial:

attempt 1: immediately
attempt 2: 30 seconds later
attempt 3: 5 minutes later
attempt 4: 30 minutes later
attempt 5: 2 hours later
attempt 6: 6 hours later
attempt 7: 24 hours later

Após 7 tentativas com falha, marcamos o evento como permanently_failed e paramos de tentar. Os eventos com falha aparecem no painel de webhooks com o último erro; você pode reenviar manualmente qualquer um deles com Tentar novamente.

O seu endpoint precisa ser idempotente. Não removemos duplicidades das novas tentativas do nosso lado: o seu endpoint verá o mesmo evento várias vezes se as primeiras tentativas deram timeout, mas acabaram sendo bem-sucedidas. Use o id do evento como chave e ignore o evento se você já o processou.

Vários endpoints

Você pode cadastrar vários endpoints (por exemplo, um para o seu CRM e outro para o seu data lake de AML). Cada um pode assinar um conjunto diferente de tipos de evento. Cada endpoint tem o seu próprio segredo de assinatura: rotacionar um não afeta os outros.

Webhooks por formulário

O webhook de toda a organização é disparado para todos os eventos relevantes. Os formulários públicos também podem ter uma URL de webhook por formulário nas suas configurações, útil quando um formulário alimenta um sistema separado. Os webhooks por formulário funcionam além dos webhooks de toda a organização.

A página KYC → Webhooks agora lista os dois em um só lugar: a URL de webhook da organização no topo e, abaixo dela, uma linha para a URL de webhook de cada formulário, para que você veja todos os destinos de entrega sem precisar procurar nas configurações de cada formulário.

O painel de webhooks

KYC → Webhooks lista todos os endpoints com:

  • URL do endpoint e nome amigável.
  • Status: ativo / pausado / com falha.
  • Última entrega: quando o evento mais recente foi enviado por POST.
  • Taxa de sucesso: % das tentativas que retornaram 2xx nos últimos 7 dias.
  • Entregas recentes: tabela de eventos recentes com código de status, latência e corpo da resposta.

Pause um endpoint para interromper as entregas sem perder a configuração.

Solução de problemas

Meu endpoint está sendo sobrecarregado

Os endpoints são chamados uma vez por evento, mas uma organização movimentada pode disparar dezenas por minuto. Torne o seu endpoint assíncrono: aceite o POST, responda 2xx imediatamente e processe o payload fora do ciclo da requisição. Se precisar nos fazer diminuir o ritmo, defina a opção Máximo de entregas simultâneas por endpoint.

A validação da assinatura continua falhando

Três causas comuns:

  1. Fazer o parsing do corpo antes de validar a assinatura. Use os bytes brutos. Quem usa Express + body-parser: defina bodyParser.raw({ type: 'application/json' }) especificamente para a rota do webhook.
  2. Segredo errado. Rotacione e cole de novo.
  3. Remover ou transformar o corpo em algum middleware (gzip, BOM, codificação). A assinatura cobre exatamente os bytes que enviamos.

Os eventos parecem duplicados

São novas tentativas por respostas lentas. Use o event.id como chave para a idempotência.

A ordem dos eventos importa, mas estou vendo eventos fora de ordem

Não garantimos uma ordem estrita entre tipos de evento. Para ordenar por solicitante, use o campo createdAt do evento; a ordem dentro do ciclo de vida de um único solicitante é monotônica.