Saltar al contenido principal

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:

  1. El usuario toca Comenzar
  2. El navegador pide permiso de cámara
  3. El usuario fotografía el frente de su documento (cámara o galería)
  4. El usuario fotografía el dorso — salvo que hayas puesto require-doc-back="false" o que el tipo de documento sea passport
  5. El usuario se saca una selfie (solo cámara)
  6. El widget corre controles de calidad, sube cada imagen a la API de Veridia y después llama a submit
  7. Recibís un evento veridia:complete con el verificationId
  8. 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.

Probar en localhost

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, y GET /v1/verify/{id} tampoco lo devuelve. Solo el webhook te lo devuelve. Persistí verificationId → tu id de usuario desde 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

PasoDóndeQué
1NavegadorControles de calidad (Laplacian, Tenengrad, Brenner) antes de enviar nada
2NavegadorUn PUT por imagen a /v1/verify/upload/{verificationId}/{role} en la API de Veridia
3WorkerValida el token de subida, verifica que los bytes sean JPEG real, los almacena
4WorkerOCR vía Workers AI — extrae nombre, número de documento, fechas
5WorkerDespacha al backend con los datos extraídos
6BackendCoincidencia facial (insightface buffalo_s)
7BackendPuntaje de prueba de vida
8BackendChecksums de MRZ y consistencia entre MRZ y zona visual
9BackendScreening AML / sanciones
10BackendPuntaje de confianza ponderado y después el veredicto
11BackendPersiste en MySQL con traza de auditoría
12BackendEncola el webhook, si hay uno configurado
Las imágenes no van a R2 desde el navegador

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

VeredictoAproximadamente cuándoQué deberías hacer
approvedConfianza ≥ 90 y sin fallas durasConfiá en el usuario, completá el onboarding
reviewConfianza entre 60 y 90, o cualquier falla dura, o un hit de sancionesMandalo a tu cola de revisión manual
rejectedConfianza por debajo de 60Bloqueá, 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ódigoSignificadoRespuesta típica
camera_deniedEl usuario rechazó el pedido de permiso de cámaraExplicale por qué lo necesitás, ofrecé un reintento
camera_unavailableNo hay cámara, o la página no está en HTTPS/localhostDecile al usuario que cambie de dispositivo o navegador
user_cancelledEl usuario tocó Cancelar y abandonó el flujoNo es un error. Registralo: es tu señal de abandono del embudo
invalid_api_keyClave faltante, mal tipeada, revocada o del entorno equivocadoCorregí tu configuración. No es para mostrarle al usuario
insufficient_creditsTu tenant se quedó sin créditosRecargá. Alertate a vos mismo: todos los usuarios quedan bloqueados hasta que lo hagas
rate_limitedSe alcanzó el límite de tasaEsperá y reintentá
api_unreachableFalla de red o 5xx de la APITransitorio. El widget ya reintentó
upload_failedFalló la subida de una imagen tras tres reintentos con backoffMostralo; suele ser una mala conexión móvil
no_face_in_selfieNo se detectó cara en la selfieReservado. Normalmente se maneja inline como pedido de repetir la foto
blurry_imageImagen demasiado borrosaReservado. Normalmente se maneja inline como pedido de repetir la foto
internal_errorCualquier cosa inesperada, incluidos errores de la API sin mapearRegistrá 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, 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.

Paso 3: Manejo de resultados →