Pular para o conteúdo principal

Webhooks

Os webhooks notificam o seu servidor sobre eventos da conta, como validações concluídas, resultados do FaceMatch e revisões resolvidas. Cada evento é enviado em uma requisição POST para a URL cadastrada.

Configuração​

No Dashboard, acesse Configurações → Webhooks e cadastre um endpoint:

CampoDescrição
URLEndereço que receberá os eventos. Somente HTTPS.
SecretChave utilizada na assinatura das requisições. Recomendado.
EventosTipos de evento enviados para o endpoint.

É possível cadastrar mais de um endpoint.

Formato da requisição​

{
"id": "evt_3f9c2a1b7d4e4c0a9b8f6e21",
"type": "validation.succeeded",
"createdAt": "2026-09-14T09:41:07.123-03:00",
"clientId": "0b7e5d3a-6c1f-4e2a-9d8b-5f4c3a2e1d0c",
"data": {
"validationType": "liveness_document",
"document": "123******01",
"deviceId": 1234,
"similarity": 92.4,
"biometricsAvailable": true,
"livenessScore": 97.8,
"requestId": "1726317667123.aB3dEf"
}
}
CampoTipoDescrição
idstringIdentificador do evento. O valor se mantém em reenvios.
typestringTipo do evento.
createdAtstringData e hora do evento (ISO 8601).
clientIdstringUUID do cliente.
dataobjectDados do evento. Campos sem valor não são enviados.

Os eventos não incluem imagens, e documentos são enviados mascarados.

Cabeçalhos​

CabeçalhoDescrição
X-BioTrust-EventTipo do evento.
X-BioTrust-Event-IdIdentificador do evento.
X-BioTrust-TimestampData e hora do envio, em segundos Unix.
X-BioTrust-AttemptNúmero da tentativa de entrega.
X-BioTrust-SignatureAssinatura da requisição, no formato sha256=<assinatura>. Enviado quando o endpoint possui secret.

Validação da assinatura​

A assinatura é o HMAC-SHA256, em hexadecimal, do texto {timestamp}.{corpo}, em que timestamp é o valor do cabeçalho X-BioTrust-Timestamp e corpo é o corpo da requisição. O secret do endpoint é utilizado como chave.

  • Calcule a assinatura sobre o corpo bruto da requisição, antes da desserialização.
  • Compare as assinaturas em tempo constante.
  • Rejeite requisições com timestamp fora da janela de tolerância definida pela sua aplicação (por exemplo, 5 minutos).

Node.js (Express)

import crypto from "node:crypto";
import express from "express";

const app = express();

app.post("/webhooks/biotrust", express.raw({ type: "application/json" }), (req, res) => {
const timestamp = req.header("X-BioTrust-Timestamp");
const assinatura = req.header("X-BioTrust-Signature") ?? "";
const corpo = req.body.toString("utf8");

const esperada = "sha256=" + crypto
.createHmac("sha256", process.env.BIOTRUST_WEBHOOK_SECRET)
.update(`${timestamp}.${corpo}`)
.digest("hex");

const dentroDaJanela = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
const valida = assinatura.length === esperada.length &&
crypto.timingSafeEqual(Buffer.from(assinatura), Buffer.from(esperada));

if (!dentroDaJanela || !valida) {
return res.sendStatus(401);
}

const evento = JSON.parse(corpo);
// Processar o evento de forma assíncrona
res.sendStatus(200);
});

C#

using System.Security.Cryptography;
using System.Text;

static bool AssinaturaValida(string timestamp, string corpo, string assinatura, string secret)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes($"{timestamp}.{corpo}"));
var esperada = "sha256=" + Convert.ToHexString(hash).ToLowerInvariant();

return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(esperada),
Encoding.UTF8.GetBytes(assinatura));
}

Política de entrega​

  • A entrega é considerada concluída quando o endpoint responde com status 2xx em até 10 segundos.
  • Em caso de falha, o evento é reenviado até completar 5 tentativas, com intervalos aproximados de 1 minuto, 5 minutos, 30 minutos e 2 horas.
  • Endpoints com falhas recorrentes são desativados e podem ser reativados no Dashboard.
  • A ordem de entrega não é garantida, e o mesmo evento pode ser recebido mais de uma vez. Utilize o campo id para tratar duplicidades.

Eventos​

EventoDescriçãoCampos de data
validation.succeededValidação aprovada.validationType, deviceId, requestId, livenessScore, ipAddress. Na validação com documento: document, similarity, biometricsAvailable.
validation.failedValidação reprovada.Os mesmos de validation.succeeded, além de reason ou errors.
validation.blocked_by_ruleValidação bloqueada por regra.validationType, rule, deviceId, requestId, document.
validation.review_requiredValidação encaminhada para revisão manual.validationType, rule, deviceId, requestId. No FaceMatch: personId, document, similarity.
facematch.matchedPessoa identificada no FaceMatch.personId, document, similarity, deviceId, requestId.
facematch.not_matchedNenhuma pessoa identificada no FaceMatch.candidates, deviceId, requestId.
facematch.person.createdPessoa cadastrada.personId, name, document.
facematch.person.updatedPessoa atualizada.personId, name, document.
facematch.person.deletedPessoa excluída.personId, name, document.
device.registeredNovo dispositivo registrado na conta.deviceId, os, osVersion, sdkVersion.
security.denylist_hitDispositivo ou documento em lista de bloqueio.validationType, deviceId, requestId, document.
security.anomaly_detectedComportamento anômalo identificado na conta.kind, deviceId, ipAddress.
security.auth_rejectedAutenticação do SDK recusada.reason, deviceId, packageName, sdkVersion, requestId.
review.resolvedRevisão concluída no Dashboard.reviewId, decision, rule, reviewedBy, notes, deviceId, document.
webhook.testEvento de teste.—