Primera verificación
Es hora de correr una verificación real con el widget que embebiste en el paso anterior.
Qué vas a probar
Un flujo de usuario completo:
- El usuario toca Comenzar
- El navegador pide permiso de cámara
- El usuario fotografía el frente de su documento (cámara o galería)
- El usuario fotografía el dorso — salvo que hayas puesto
require-doc-back="false"o que el tipo de documento seapassport - El usuario se saca una selfie (solo cámara)
- El widget corre controles de calidad, sube cada imagen a la API de Veridia y después llama a submit
- Recibís un evento
veridia:completecon elverificationId - El veredicto (
approved/review/rejected) se calcula del lado del servidor unos instantes después
Corrélo
Abrí la página donde embebiste el widget. Usá un dispositivo real con cámara — el widget es mobile-first, pero también funciona en notebooks.
No hay nada que configurar. Las claves se crean con la lista de orígenes permitidos vacía, y una lista vacía permite todos los orígenes, localhost incluido. Si el widget se niega a arrancar, la causa está en otro lado; mirá e.detail.code en el evento veridia:error.
Consejos para la captura del documento
- Apoyá el documento plano sobre una superficie que contraste (evitá blanco sobre blanco)
- No tapes ninguna esquina con los dedos
- Evitá la luz directa reflejando sobre el documento — eso levanta el flag
heavy_glare - Asegurate de que el documento entre completo en el cuadro
- Sostené el celular firme; los cuadros borrosos los rechaza el control de calidad antes de subirlos
Consejos para la selfie
- Mirá directo a la cámara
- Buena iluminación pareja (sin contraluz)
- Sacate los anteojos de sol y las gorras que tapen la cara
- Quedate quieto durante la captura
Inspeccioná el payload del evento
Agregá listeners para ver exactamente qué emite el widget. Estos dos son los únicos eventos que el widget despacha:
<script>
const w = document.querySelector('veridia-widget');
w.addEventListener('veridia:complete', (e) => {
console.log('verification complete:', e.detail);
});
w.addEventListener('veridia:error', (e) => {
console.error('verification error:', e.detail);
});
</script>
Cuando el usuario termina, tu consola muestra exactamente dos campos:
{
"verificationId": "vf_AG07CDWRRFQV4T05ZXG2",
"status": "queued"
}
Eso es todo. En este evento no hay userRef ni veredicto.
- Sin
userRef: el widget no lo copia al evento, yGET /v1/verify/{id}tampoco lo devuelve. Solo el webhook te lo devuelve. PersistíverificationId → tu id de usuariodesde este handler, o vas a terminar con un veredicto que no podés atribuir a nadie. - Sin veredicto:
status: "queued"describe el pipeline, no a la persona. Traé el veredicto desde tu servidor (paso 3) o recibilo por webhook.
Miralo en tu panel
Andá a tu panel de Veridia y abrí la cola de revisión. Vas a ver tu verificación con:
- Datos de quien la envió (user ref, fecha y hora de envío)
- Los seis puntajes: confianza del OCR, coincidencia facial, prueba de vida, calidad del documento, validez de MRZ y coincidencia de nombre
- Flags, cada uno con un nivel y un texto (por ejemplo
heavy_glare,possible_screen_capture) - La confianza general y el veredicto final
Entrá a una verificación para ver el desglose completo y las imágenes capturadas.
Qué pasa detrás de escena
| Paso | Dónde | Qué |
|---|---|---|
| 1 | Navegador | Controles de calidad (Laplacian, Tenengrad, Brenner) antes de enviar nada |
| 2 | Navegador | Un PUT por imagen a /v1/verify/upload/{verificationId}/{role} en la API de Veridia |
| 3 | Worker | Valida el token de subida, verifica que los bytes sean JPEG real, los almacena |
| 4 | Worker | OCR vía Workers AI — extrae nombre, número de documento, fechas |
| 5 | Worker | Despacha al backend con los datos extraídos |
| 6 | Backend | Coincidencia facial (insightface buffalo_s) |
| 7 | Backend | Puntaje de prueba de vida |
| 8 | Backend | Checksums de MRZ y consistencia entre MRZ y zona visual |
| 9 | Backend | Screening AML / sanciones |
| 10 | Backend | Puntaje de confianza ponderado y después el veredicto |
| 11 | Backend | Persiste en MySQL con traza de auditoría |
| 12 | Backend | Encola el webhook, si hay uno configurado |
Puede que veas material más viejo que describe subidas prefirmadas directo a Cloudflare R2. No es lo que pasa. Cada imagen se manda con PUT a la propia API de Veridia, autenticada por un X-Veridia-Upload-Token de vida corta que /v1/verify/init devuelve dentro de los headers de cada slot de subida. La API valida y almacena los bytes.
Esto importa en dos lugares. Si estás endureciendo una Content Security Policy, el host que tenés que permitir es api.xxuxe.online, no un dominio de R2 — poner R2 en la lista te va a bloquear las subidas. Y si alguna vez escribís un cliente a mano en vez de usar el widget, tenés que reenviar los headers del slot tal cual; tu clave de API no autentica ese endpoint, y armar el request por tu cuenta sin el token de subida devuelve un 400 en cada imagen.
Qué significa el veredicto
| Veredicto | Aproximadamente cuándo | Qué deberías hacer |
|---|---|---|
approved | Confianza ≥ 90 y sin fallas duras | Confiá en el usuario, completá el onboarding |
review | Confianza entre 60 y 90, o cualquier falla dura, o un hit de sanciones | Mandalo a tu cola de revisión manual |
rejected | Confianza por debajo de 60 | Bloqueá, pedile al usuario que reintente, o escalá |
Dos reglas que vale la pena internalizar, porque no se ven desde el número de confianza solo:
- Una falla dura nunca auto-aprueba. Sin cara en el documento, sin cara en la selfie, un checksum de MRZ fallido, un spoof detectado — cualquiera de estos fuerza al menos
review, diga lo que diga el puntaje. - Una coincidencia de sanciones fuerza
review, nunca un rechazo automático. Se espera que esa decisión la tome una persona.
Estos umbrales son parámetros a nivel de todo el despliegue, no perillas por tenant. No reimplementes la clasificación de tu lado a partir de confidence; leé verdict y actuá según eso.
Códigos de error que emite el widget
Estos son los valores reales de e.detail.code en veridia:error. La lista completa:
| Código | Significado | Respuesta típica |
|---|---|---|
camera_denied | El usuario rechazó el pedido de permiso de cámara | Explicale por qué lo necesitás, ofrecé un reintento |
camera_unavailable | No hay cámara, o la página no está en HTTPS/localhost | Decile al usuario que cambie de dispositivo o navegador |
user_cancelled | El usuario tocó Cancelar y abandonó el flujo | No es un error. Registralo: es tu señal de abandono del embudo |
invalid_api_key | Clave faltante, mal tipeada, revocada o del entorno equivocado | Corregí tu configuración. No es para mostrarle al usuario |
insufficient_credits | Tu tenant se quedó sin créditos | Recargá. Alertate a vos mismo: todos los usuarios quedan bloqueados hasta que lo hagas |
rate_limited | Se alcanzó el límite de tasa | Esperá y reintentá |
api_unreachable | Falla de red o 5xx de la API | Transitorio. El widget ya reintentó |
upload_failed | Falló la subida de una imagen tras tres reintentos con backoff | Mostralo; suele ser una mala conexión móvil |
no_face_in_selfie | No se detectó cara en la selfie | Reservado. Normalmente se maneja inline como pedido de repetir la foto |
blurry_image | Imagen demasiado borrosa | Reservado. Normalmente se maneja inline como pedido de repetir la foto |
internal_error | Cualquier cosa inesperada, incluidos errores de la API sin mapear | Registrá el e.detail completo e investigá |
Dos cosas de esa tabla son fáciles de malinterpretar:
camera_denied y user_cancelled son los que más vas a ver en la práctica. Juntos explican la mayoría de los flujos abandonados en tráfico real. Ninguno de los dos es un bug, y los dos necesitan una respuesta de producto y no una pantalla de error.
El borroso y el "sin cara" normalmente no son eventos. El widget los maneja inline: le dice al usuario que repita la foto y, después de dos fallas consecutivas sobre la misma toma, deja pasar la foto igual en vez de dejar al usuario atrapado en un loop. Así que no armes tu telemetría de calidad de imagen sobre estos códigos — va a quedar vacía. upload_failed, en cambio, sí llega a tu handler una vez agotados los reintentos, así que dejale una alerta configurada.
Paso siguiente
Ya tenés un resultado de verificación. Ahora aprendé a leer el veredicto.