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:
| Campo | Descrição |
|---|---|
| URL | Endereço que receberá os eventos. Somente HTTPS. |
| Secret | Chave utilizada na assinatura das requisições. Recomendado. |
| Eventos | Tipos 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"
}
}
| Campo | Tipo | Descrição |
|---|---|---|
id | string | Identificador do evento. O valor se mantém em reenvios. |
type | string | Tipo do evento. |
createdAt | string | Data e hora do evento (ISO 8601). |
clientId | string | UUID do cliente. |
data | object | Dados 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çalho | Descrição |
|---|---|
X-BioTrust-Event | Tipo do evento. |
X-BioTrust-Event-Id | Identificador do evento. |
X-BioTrust-Timestamp | Data e hora do envio, em segundos Unix. |
X-BioTrust-Attempt | Número da tentativa de entrega. |
X-BioTrust-Signature | Assinatura 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
2xxem 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
idpara tratar duplicidades.
Eventos
| Evento | Descrição | Campos de data |
|---|---|---|
validation.succeeded | Validação aprovada. | validationType, deviceId, requestId, livenessScore, ipAddress. Na validação com documento: document, similarity, biometricsAvailable. |
validation.failed | Validação reprovada. | Os mesmos de validation.succeeded, além de reason ou errors. |
validation.blocked_by_rule | Validação bloqueada por regra. | validationType, rule, deviceId, requestId, document. |
validation.review_required | Validação encaminhada para revisão manual. | validationType, rule, deviceId, requestId. No FaceMatch: personId, document, similarity. |
facematch.matched | Pessoa identificada no FaceMatch. | personId, document, similarity, deviceId, requestId. |
facematch.not_matched | Nenhuma pessoa identificada no FaceMatch. | candidates, deviceId, requestId. |
facematch.person.created | Pessoa cadastrada. | personId, name, document. |
facematch.person.updated | Pessoa atualizada. | personId, name, document. |
facematch.person.deleted | Pessoa excluída. | personId, name, document. |
device.registered | Novo dispositivo registrado na conta. | deviceId, os, osVersion, sdkVersion. |
security.denylist_hit | Dispositivo ou documento em lista de bloqueio. | validationType, deviceId, requestId, document. |
security.anomaly_detected | Comportamento anômalo identificado na conta. | kind, deviceId, ipAddress. |
security.auth_rejected | Autenticação do SDK recusada. | reason, deviceId, packageName, sdkVersion, requestId. |
review.resolved | Revisão concluída no Dashboard. | reviewId, decision, rule, reviewedBy, notes, deviceId, document. |
webhook.test | Evento de teste. | — |