Receba o resultado por webhook
Em vez de consultar a verificação em laço, cadastre um endpoint e receba um POST assinado assim que a decisão sai. Cada entrega leva a assinatura HMAC-SHA256 e um carimbo de tempo para você conferir a origem.
Documentação › Webhooks
1. Cadastre o endpoint
Cadastre pelo console, em Webhooks, ou pela API. O destino precisa ser público e responder em HTTPS; endereços internos são recusados na hora do cadastro.
curl -X POST https://api.provalidface.com.br/api/v1/webhooks \
-H "Authorization: Bearer vf_test_sua_chave_de_teste" \
-H "Content-Type: application/json" \
-d '{"url": "https://api.suaempresa.com.br/webhooks/validface", "description": "Produção"}'
A resposta 201 traz o secret de assinatura uma única vez. Guarde agora: ele não volta a ser exibido e fica cifrado no banco.
{
"id": "9a0f...",
"url": "https://api.suaempresa.com.br/webhooks/validface",
"description": "Produção",
"is_active": true,
"created_at": "2026-09-30T12:00:00Z",
"secret": "troque_pelo_segredo_que_veio_na_resposta",
"aviso": "Guarde o segredo agora: ele nao volta a ser exibido."
}
2. Eventos entregues
A plataforma entrega três eventos ao seu endpoint. O corpo repete os campos de decisão (status, score, reasons) e acrescenta o campo event. O formato difere do GET da verificação: não traz session_url nem a lista de etapas.
| Evento | Quando | Conteúdo |
|---|---|---|
verification.completed | A verificação foi decidida automaticamente pelo pipeline. | Traz status (approved, rejected ou review), score e reasons. |
verification.expired | A sessão passou do prazo sem o titular concluir. | status expired; nenhuma etapa decidiu a sessão. |
verification.reviewed | Um analista da sua empresa fechou um caso na revisão manual. | status final approved ou rejected, com MANUAL_REVIEW_* no fim de reasons. |
Os demais registros verification.* (por exemplo verification.decided) ficam na trilha de auditoria interna e não são enviados por webhook.
3. Verifique a assinatura
Cada entrega chega com dois cabeçalhos:
X-ValidFace-Signature: o valorsha256=<hmac>.X-ValidFace-Timestamp: o instante do envio, em segundos desde a época (Unix).
A assinatura cobre o carimbo de tempo mais o corpo bruto, nesta forma, o que impede reaproveitar um corpo válido com data antiga:
sha256 = HMAC_SHA256(secret, f"{timestamp}." + corpo_bruto)
Recalcule com o segredo do endpoint sobre o corpo exatamente como chegou (não reserialize o JSON) e compare em tempo constante:
import hashlib
import hmac
def assinatura_confere(secret, corpo_bruto, timestamp, cabecalho_assinatura):
esperado = "sha256=" + hmac.new(
secret.encode(),
f"{timestamp}.".encode() + corpo_bruto,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(esperado, cabecalho_assinatura)
Exemplo conferível
Com o segredo whsec_exemplo_troque_pelo_segredo_do_seu_endpoint, o cabeçalho X-ValidFace-Timestamp: 1730419200 e o corpo abaixo:
{"cost": "0.52", "created_at": "2026-09-30T12:00:00+00:00", "decided_at": "2026-09-30T12:00:07+00:00", "engine_versions": {"cpf": "[email protected]", "document_classify": "[email protected]", "face_match": "[email protected]", "liveness": "[email protected]", "ocr": "[email protected]"}, "event": "verification.completed", "external_reference": "pedido-1042", "id": "3f1c8e0a-9d4b-4c2e-8a10-2b7c5e9f0a11", "journey": "padrao", "reasons": [{"code": "APPROVED", "message": "Verificacao aprovada."}], "score": 95, "status": "approved"}
A assinatura é:
X-ValidFace-Signature: sha256=7ee06d5f42a1f03ad3845fc86b2a8cf9481c051f3fa4161f68158b358fde841a
Este valor foi calculado pela mesma função que assina as entregas em produção.
4. Retentativas e idempotência
Responda 2xx para confirmar o recebimento. Sem isso, a entrega é reagendada com espera progressiva, até 5 tentativas, e então marcada como falha. Há uma entrega por combinação de verificação, endpoint e evento, então a reexecução do pipeline não vira dois POST do mesmo evento. Ainda assim, trate o recebimento de forma idempotente pelo id da verificação: registre o que já processou e ignore a repetição.
5. Reenvie uma entrega
Se o seu endpoint ficou fora do ar e a entrega esgotou as tentativas, reenvie pelo console ou pela API. O reenvio zera as tentativas, volta a entrega para a fila e responde 202.
curl -X POST https://api.provalidface.com.br/api/v1/webhooks/deliveries/ID_DA_ENTREGA/resend \
-H "Authorization: Bearer vf_test_sua_chave_de_teste"
Uma entrega ainda em andamento responde 409 (nenhum reenvio disparado, para não gerar POST duplo); fila indisponível responde 503 e a entrega fica pendente para reenvio automático.
6. Teste local com um túnel
O destino precisa ser público, então em desenvolvimento use um túnel para expor a sua máquina: cloudflared tunnel --url http://localhost:8000 ou ngrok http 8000 geram uma URL HTTPS temporária. Cadastre essa URL como endpoint e dispare uma verificação de sandbox para ver o POST chegar.