Referencia de la API
Veridia expone una API REST chica. JSON in, JSON out. Sin SOAP, sin GraphQL, sin XML.
Base URL
https://api.xxuxe.online
Todas las requests deben usar HTTPS.
Endpoints
| Método | Path | Auth | Propósito |
|---|---|---|---|
POST | /v1/verify/init | Clave de API | Inicia una verificación, obtiene los slots de subida |
PUT | /v1/verify/upload/:verificationId/:role | Token de subida | Sube una imagen |
GET | /v1/verify/challenge/:verificationId/next | Token de subida | Próxima baliza de prueba de vida activa (solo en flujos que la activan) |
POST | /v1/verify/submit | Clave de API | Corre el pipeline sobre las imágenes subidas |
GET | /v1/verify/:id | Clave de API — solo secreta | Consulta el status y el veredicto |
GET | /health | Ninguna | Liveness check |
El widget usa todos estos endpoints por debajo. Vos los llamás directamente cuando estás armando un flujo server-side o un cliente móvil propio.
Dos de ellos son fáciles de pasar por alto, y los dos son estructurales:
PUT /v1/verify/upload/...es por donde pasa cada byte de imagen del producto. No toma bearer token. Ver POST /v1/verify/init.GET /v1/verify/challenge/.../nextsolo existe en flujos que optaron por prueba de vida activa conactiveLiveness: trueen/init.
No existe /v1/verifications ni /v1/verifications/:id. Esos paths devuelven 404 not_found; el endpoint de resultados es GET /v1/verify/:id.
Autenticación
La mayoría de los endpoints toman un bearer token:
Authorization: Bearer qv_pub_FJJWXMA2RN2XPRDK6YJX4KTVD0XSQHW9
Existen dos familias de claves, y esa división es lo más importante de esta página:
| Familia | Prefijo live | Prefijo test | Dónde corre | ¿Puede leer veredictos? |
|---|---|---|---|---|
| Publicable | qv_pub_ | qv_pubt_ | Navegador, widget, app móvil | No |
| Secreta | qv_sec_ | qv_sect_ | Solo tu servidor | Sí |
Una clave publicable puede iniciar una verificación y enviarla. No puede leer el resultado — GET /v1/verify/:id la rechaza con 401 secret_key_required. Eso es deliberado: una clave publicable vive en el código fuente de tu página, donde cualquiera puede leerla, así que nunca debe poder obtener un veredicto KYC.
Prestá atención a los prefijos de test: qv_pubt_ y qv_sect_. No qv_pub_test_.
Los endpoints de subida y de reto no usan ninguna de las dos. Se autentican con el X-Veridia-Upload-Token de vida corta que /init devuelve dentro del objeto headers de cada slot de subida.
Detalle completo: Autenticación.
Versionado
La API se versiona en el path de la URL: /v1/.... Los cambios incompatibles van a un path de versión nuevo (/v2/...).
Los agregados compatibles — campos opcionales nuevos en las requests, campos nuevos en las respuestas, endpoints nuevos — pasan en /v1 sin aviso. Escribí clientes que ignoren los campos de respuesta que no reconocen.
Formato de las requests
Todos los bodies POST son JSON:
POST /v1/verify/init HTTP/1.1
Host: api.xxuxe.online
Authorization: Bearer qv_pub_...
Content-Type: application/json
{
"userRef": "customer-12345",
"country": "PY",
"documentType": "dni"
}
Los bodies de las requests se validan con un esquema no estricto. Una clave que no reconocemos se descarta sin error — recibís 200 OK y el valor simplemente desapareció.
Así que si te inventás un campo (tenantId, callbackUrl, metadata en /init) nada te avisa que no tuvo efecto. Revisá las tablas de campos de cada página de endpoint en lugar de asumir que un campo funcionó porque la request salió bien.
Formato de las respuestas
Toda respuesta lleva un requestId, y el mismo valor está en el header de respuesta X-Request-Id — así podés correlacionar incluso cuando falla el parseo del JSON. Registralo. Es el camino más rápido a un diagnóstico en un ticket de soporte.
{
"verificationId": "vf_AG07CDWRRFQV4T05ZXG2",
"uploads": { "docFront": { "...": "..." } },
"expiresAt": 1714604000
}
Los errores usan una forma consistente:
{
"error": "invalid_body",
"message": "Request body failed validation",
"requestId": "9f511d92ac11236d-SJC",
"detail": {
"fieldErrors": {
"country": ["expected 2 characters"]
}
}
}
Ramificá sobre error, no sobre el status HTTP. Ver Errores para el catálogo completo.
Status no es veredicto
El error más caro que permite esta API:
| Campo | Eje | Valores |
|---|---|---|
status | ¿Corrió el pipeline? | queued, processing, completed, failed |
verdict | ¿Pasó la persona? | approved, review, rejected |
status: "completed" significa que el pipeline terminó. No dice nada sobre si el solicitante fue aceptado. Ramificar sobre status para dar de alta una cuenta admite a todos los solicitantes rechazados, en silencio, sin ningún error en ningún lado.
// MAL — esto da de alta a todos los que el sistema rechazó
if (result.status === 'completed') enableAccount(userId);
// BIEN
if (result.status === 'completed' && result.verdict === 'approved') enableAccount(userId);
verdict está ausente (o en null) hasta que status sea completed. Detalles en GET /v1/verify/:id.
Límites de tasa
Dos capas. La que agarra desprevenida a la gente es la capa por IP, que se verifica antes de leer tu clave:
| Capa | Límite |
|---|---|
| Por IP de cliente, todas las rutas | 100 requests / 60 s |
Por tenant — /v1/verify/init | 60 / 60 s |
Por tenant — /v1/verify/submit | 30 / 60 s |
Por tenant — /v1/verify/:id | 600 / 60 s |
Una verificación con prueba de vida activa hace unas 26 requests desde el dispositivo del usuario, así que un puñado de usuarios móviles detrás de una misma dirección CGNAT puede agotar el presupuesto por IP mientras tus contadores de tenant se ven ociosos. La explicación completa, y qué hacer al respecto, está en Límites de tasa — leelo antes de salir a producción con tráfico móvil.
Las respuestas 429 llevan un header Retry-After.
CORS
Las respuestas de preflight (OPTIONS) se cachean 10 minutos.
Las requests cross-origin no están restringidas por defecto. Una clave publicable puede llevar una lista de orígenes permitidos, pero toda clave se crea con esa lista vacía, y una lista vacía permite todos los orígenes. Tratala como una forma de acotar dónde corre tu widget una vez que la completes — no como un control de acceso. Ver la advertencia en Autenticación.
A dónde seguir
- Autenticación — familias de claves, entornos, qué hace y qué no hace la lista de orígenes
- POST /v1/verify/init — iniciar una verificación, y cómo funcionan realmente las subidas
- POST /v1/verify/submit — correr el pipeline
- GET /v1/verify/:id — obtener el veredicto
- Errores — referencia de códigos de error
- Límites de tasa — los dos límites, y la salvedad de CGNAT