Webhooks
Los webhooks son como Veridia te pushea los resultados de verificacion al backend en el momento que estan listos. Push, no poll. Firmados, no anonimos. Reintentados, no best-effort.
Esta es la forma recomendada de consumir veredictos en produccion.
Por que webhooks le ganan al polling
| Aspecto | Polling | Webhooks |
|---|---|---|
| Latencia desde completion a tu codigo | 1-3 segundos (intervalo de poll) | <200ms |
| API calls por verificacion | 3-30 | 1 |
| Confiabilidad si tu servicio cae | Lo perdes | Reintentamos 5 veces |
| Audit trail | Ninguno | Log completo de delivery en dashboard |
| Costo (tu factura serverless) | Cold start cada poll | Una invocacion |
El event handler del widget sigue funcionando para feedback UX client-side ("Enviado!"), pero el veredicto deberia llegar via webhook.
Setup
- Inicia sesion en tu dashboard de Veridia
- Abri Webhooks → Endpoints
- Agrega un nuevo endpoint:
- URL:
https://tuapp.com/webhooks/veridia(HTTPS obligatorio en produccion) - Events: selecciona que eventos recibir (o "All")
- Description: label interno opcional
- URL:
- Copia el webhook secret — vas a necesitarlo para verificar firmas. Se muestra solo una vez.
- Guarda
Eso es todo. La proxima verificacion que complete dispara un POST a tu URL.
Que recibis
Cada webhook es una request POST con:
POST /webhooks/veridia HTTP/1.1
Host: tuapp.com
Content-Type: application/json
Veridia-Signature: t=1714604000,v1=4f8a3b9c...
Veridia-Event: verification.approved
User-Agent: Veridia-Webhooks/1.0
{
"event": "verification.approved",
"verificationId": "vf_AG07CDWRRFQV4T05ZXG2",
"tenantId": "tn_default_demo",
"userRef": "customer-12345",
"verdict": "approved",
"confidence": 87.4,
"scores": {
"ocrConfidence": 78.0,
"faceMatch": 96.2,
"liveness": 91.5,
"docQuality": 85.0
},
"flags": [],
"metadata": {},
"submittedAt": "2026-05-01T18:39:05Z",
"completedAt": "2026-05-01T18:39:08Z"
}
El body es JSON compacto con keys ordenadas alfabeticamente — requerido para la verificacion reproducible de la firma.
Tipos de eventos
| Event | Verdict | Cuando |
|---|---|---|
verification.approved | approved | Alta confianza, todas las senales pasan |
verification.rejected | rejected | Baja confianza o flag critico |
verification.review_required | review | Confianza media, revision manual recomendada |
Schemas completos: Tipos de eventos.
Requerido: responde 2xx rapido
Tu endpoint debe responder con 2xx dentro de 10 segundos. Ese es el timeout que usamos antes de considerar la delivery fallida.
Si tu handler hace trabajo pesado (writes a DB, mandar emails, llamar otras APIs), hacelo despues de responder:
// Express
app.post('/webhooks/veridia', async (req, res) => {
// 1. Verificar firma (rapido)
if (!verifySignature(req)) {
return res.status(401).send('Firma invalida');
}
// 2. Acknowledge inmediatamente
res.status(200).send('ok');
// 3. Trabajo pesado pasa despues de la respuesta
await processVerificationAsync(req.body);
});
Este es el patron estandar para cualquier sistema de webhooks (Stripe, GitHub, etc.).
Politica de reintentos
Si tu endpoint devuelve un status no-2xx, hace timeout, o es inaccesible, Veridia reintenta con backoff exponencial:
| Intento | Espera antes de reintentar |
|---|---|
| 1 | (inmediato) |
| 2 | 1 segundo |
| 3 | 5 segundos |
| 4 | 30 segundos |
| 5 | 2 minutos |
| (final) | 10 minutos |
Despues de 5 intentos fallidos, la delivery se marca failed en el dashboard. Podes re-encolarla manualmente desde ahi.
Una respuesta 4xx (excepto 408 Request Timeout y 429 Too Many Requests) se trata como falla permanente — no reintentamos, porque reintentar no va a ayudar.
Verificando firmas
Siempre verifica el header Veridia-Signature antes de confiar en el contenido del webhook. De otro modo, un atacante que conoce tu URL podria forjar eventos.
El formato es:
Veridia-Signature: t=1714604000,v1=4f8a3b9c01ee...
Dos partes:
t=<unix_timestamp>— cuando enviamos el webhookv1=<hex_hmac>— HMAC-SHA256 de<timestamp>.<raw_body>usando tu webhook secret
Algoritmo completo + code samples: Verificacion de firma.
Idempotencia
Entregamos el mismo evento a lo sumo una vez en condiciones normales, pero durante retries es posible recibir un duplicado. Hace tu handler idempotente:
async function handleWebhook(payload) {
// Usa verificationId + event como dedup key
const key = `${payload.verificationId}:${payload.event}`;
if (await wasAlreadyProcessed(key)) {
return; // Ya manejado
}
await processVerification(payload);
await markAsProcessed(key);
}
Best practices
- Verifica la firma antes de confiar en el body. Siempre.
- Responde
2xxdentro de 10 segundos incluso si encolas el trabajo para despues - Valida que el timestamp este dentro de 5 minutos (proteccion replay)
- Hace tu handler idempotente usando
verificationId + eventcomo dedup key - Loguea el
verificationIden cada webhook — mas facil de rastrear despues - Usa HTTPS en produccion (entregamos a HTTP solo en test mode para localhost)
- Whitelist IPs de Veridia si tenes reglas de egress (contacta soporte por la lista actual)
Test de webhooks localmente
Los webhooks no pueden alcanzar localhost directamente. Usa un servicio de tunneling:
| Herramienta | Costo | Notas |
|---|---|---|
| ngrok | Tier gratis disponible | El mas popular |
| localtunnel | Gratis | Open source |
| Cloudflare Tunnel | Gratis | Mejor para dev production-grade |
Ejemplo rapido con ngrok:
ngrok http 3000
# Forwarding https://abc123.ngrok.io -> localhost:3000
# Despues usa https://abc123.ngrok.io/webhooks/veridia en tu dashboard
Que sigue
- Verificacion de firma — algoritmo exacto con code samples
- Tipos de eventos — schemas completos para cada evento
- Ejemplos — implementaciones de handler completas en Node.js, Python, PHP