Sesiones de Verificación
Una sesión representa una verificación de identidad. Al crearla se devuelve una widgetUrl que usted entrega a su cliente, y un sessionId que usa para correlacionar el resultado.
Crear una Sesión
Endpoint: POST /v1/sessions
Autenticación: token Bearer con el scope sessions
curl --request POST \
--url https://{FQDN}/v1/sessions \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"userRef": "user-123",
"language": "es",
"delivery": { "mode": "webhook" }
}'
{
"sessionId": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
"status": "pending",
"widgetUrl": "https://{FQDN}/verify/8Kd2mQ…",
"expiresAt": "2026-08-02T15:02:11.481Z"
}
Campos de la Solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
userRef | string (1-255) | Sí | Su identificador de la persona que se verifica. Se devuelve en cada resultado |
prefill | object | No | Datos conocidos sobre la persona — vea Prefill |
dataCheck | boolean | No | false (predeterminado) verifica el documento tal como se presenta. true además compara los datos extraídos contra prefill — vea Verificaciones de Datos |
delivery | object | No | Cómo le llega el resultado. El valor predeterminado es {"mode": "webhook"} |
language | string | No | Idioma del widget, xx o xx-XX (p. ej. en, pt, es, pt-BR). Recurre a su valor predeterminado configurado |
maxCaptureAttempts | integer (1-10) | No | Anula el valor predeterminado de su tenant solo para esta sesión. Se aplica por tipo de captura — este número de intentos de documento y el mismo de selfie |
Campos de la Respuesta
| Campo | Descripción |
|---|---|
sessionId | Úselo para correlacionar resultados y para llamar a GET /v1/sessions/{sessionId} |
status | pending al crearse, salvo que un escenario de sandbox termine la sesión de inmediato |
widgetUrl | El enlace de cara al cliente. Contiene un código de un solo uso válido por 48 horas — vea Vencimiento de la Sesión |
expiresAt | El plazo de la sesión, una marca de tiempo ISO 8601 en UTC — vea Vencimiento de la Sesión |
Prefill
prefill transporta lo que usted ya sabe sobre la persona. Tiene dos efectos distintos.
| Campo | Efecto |
|---|---|
documentType | passport, drivers_license o identity_card. Bloquea el widget a este documento — se omite la pantalla de selección de tipo, y un documento diferente es rechazado. Omítalo para dejar que el cliente elija |
documentNumber | Se valida su formato en esta llamada (vea abajo), y queda disponible para verificación cruzada |
issuingState | Solo la subdivisión — código o nombre de estado de EE. UU. Afina la validación de formato de una licencia. Requiere issuingCountry: PA es tanto Pará como Pennsylvania, así que una subdivisión enviada sola se rechaza con 422. Un código de país aquí no nombra nada y nunca se compara con el documento, porque los pasaportes y cédulas de identidad no evidencian subdivisión alguna |
issuingCountry | ISO 3166-1 alpha-3 — tres letras. El único campo que nombra la jurisdicción emisora, y contra el que se verifican sus jurisdicciones aceptadas. Un código que no podemos situar no resuelve nada, así que una sesión que lo declara se juzga solo por el documento |
nationality | ISO 3166-1 alpha-3 — tres letras. Disponible para verificación cruzada con el documento. Nunca resuelve la jurisdicción emisora — la nacionalidad no es emisión, en ningún tipo de documento |
firstName, lastName | Disponibles para verificación cruzada |
dateOfBirth | YYYY-MM-DD. Disponible para verificación cruzada |
Cada campo de prefill es una cadena de como máximo 255 caracteres. Envíe un campo solo cuando tenga un valor para él: un valor en blanco o solo con espacios se rechaza en lugar de ignorarse, para que un campo que no proporcionó nunca se reporte como uno con el que el documento discrepó.
{
"userRef": "user-123",
"prefill": {
"documentType": "drivers_license",
"issuingCountry": "USA",
"issuingState": "PA",
"documentNumber": "31612967",
"firstName": "Ana",
"lastName": "Silva",
"dateOfBirth": "1988-03-04"
}
}
Los campos de prefill distintos de documentType no cambian la decisión a menos que configure dataCheck: true. Sin él, los valores se transportan para comparación y se reportan en el resultado, pero una discrepancia no enruta la sesión a ninguna parte.
Sin embargo, prefill.documentNumber sí se valida en esta llamada: un número que una regla puede refutar — un dígito verificador que falla, o un valor que ninguna jurisdicción podría emitir — se rechaza con 422 en lugar de aceptarse y fallar después. Un número que simplemente no coincide con ninguna de las formas que mantenemos para su jurisdicción no se rechaza; se transporta, y el resultado publica document_number_valid como undetermined. Verifique un número antes de llegar aquí con el endpoint validador.
Verificaciones de Datos
Configure dataCheck: true para verificar que el documento pertenece a la persona que usted esperaba — no solo que el documento es genuino.
{
"userRef": "user-123",
"dataCheck": true,
"prefill": {
"firstName": "Ana",
"lastName": "Silva",
"dateOfBirth": "1988-03-04"
}
}
Con dataCheck: true:
- Los datos extraídos se comparan campo por campo contra el payload de prefill.
- El resultado incluye
prefillComparison(resultados por campo, incluidos puntajes de coincidencia difusa de nombres) yprefillMismatches(los nombres de los campos que discreparon). - Una discrepancia agrega una verificación
document_data_matchfallida y se reporta en el resultado.
Los nombres se comparan con coincidencia difusa contra un umbral de similitud configurable, de modo que las variaciones ordinarias de ortografía y transliteración no generan falsas discrepancias. dataCheck: true sin un payload de prefill es un 422 — no habría nada contra qué comparar.
Entrega
| Modo | Campos | Comportamiento |
|---|---|---|
webhook (predeterminado) | — | El resultado se envía vía POST a su webhookUrl configurada |
redirect | redirectUrl (requerido) | El cliente es devuelto a su URL con el resultado y una firma |
{ "delivery": { "mode": "redirect", "redirectUrl": "https://you.example/kyc-done" } }
Solicitar el modo webhook sin una webhookUrl configurada para su tenant es un 422. Consulte Recepción de Resultados para la verificación de firmas en ambos modos.
Respuestas de Error
Todas estas devuelven 422 con errorCode: "validation_error"; errors[] nombra el campo y la causa:
| Causa | Notas |
|---|---|
delivery.mode es webhook pero no hay una webhookUrl configurada | Pida a Inyo registrar su endpoint, o use el modo redirect |
Falta delivery.redirectUrl en modo redirect | Requerido siempre que mode sea redirect |
documentType no está habilitado para su tenant | El mensaje lista los tipos de documento que puede solicitar |
| La jurisdicción emisora del documento no está aceptada para ese tipo de documento | El mensaje lista las jurisdicciones que usted acepta |
prefill.documentNumber fue refutado por su regla | Solo una falla demostrable — un dígito verificador, o un valor que ninguna jurisdicción podría emitir. El mensaje nombra la regla, nunca el número |
dataCheck: true sin payload de prefill | Proporcione al menos un campo de prefill comparable |
| Un campo de prefill está en blanco o contiene solo espacios | Omita el campo. Un blanco no es "sin valor" — se compararía con el documento y se reportaría como discrepancia |
| Un campo de prefill tiene más de 255 caracteres | El mismo límite que userRef |
prefill.issuingState enviado sin prefill.issuingCountry | Una subdivisión no nombra nada por sí sola — el mismo código existe en más de un país |
issuingCountry o nationality no tiene tres letras | Los nombres de país y los códigos de dos letras se rechazan — envíe el código ISO 3166-1 alpha-3. Los códigos de espécimen y de apátrida (UTO, XXA, XKX) se aceptan, así que la verificación es la forma, no una lista de países |
dateOfBirth no es una fecha real en YYYY-MM-DD | 1987-13-45 coincide con la forma y no es una fecha |
| Un nombre de campo no reconocido en cualquier parte de la petición | Se rechaza en lugar de ignorarse, para que un dataCheck mal escrito no apague la comparación en silencio. Las grafías en camelCase y snake_case de campos reales se aceptan ambas |
userRef o un campo de prefill contiene un NUL (\u0000) | El valor no puede almacenarse. Los acentos, la puntuación y los espacios dentro de un valor son aceptables — este es el único carácter que no lo es |
Las fallas de autenticación y autorización devuelven 401 o 403 — vea Autenticación.
Consultar una Sesión
Endpoint: GET /v1/sessions/{sessionId}
Autenticación: token Bearer con el scope sessions
Este es el registro autoritativo de una sesión de widget. Léalo cuando necesite una garantía en lugar de un push, para recuperar un webhook que pudo haber perdido, o para leer el resultado de una sesión que fue a revisión manual.
Una verificación creada con POST /v1/verifications no se sirve aquí — tiene una lectura propia en GET /v1/verifications/{verificationId}, accesible con el scope verifications. Pasar una de ellas aquí devuelve 404.
curl --request GET \
--url https://{FQDN}/v1/sessions/$SESSION_ID \
--header "Authorization: Bearer $ACCESS_TOKEN"
{
"sessionId": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
"userRef": "user-123",
"status": "completed",
"step": "done",
"deliveryMode": "webhook",
"result": { "…": "the normalized result, updated in place" },
"createdAt": "2026-07-31T14:02:11.481Z",
"updatedAt": "2026-07-31T14:04:57.902Z",
"expiresAt": "2026-08-02T15:02:11.481Z"
}
| Campo | Descripción |
|---|---|
status | pending, completed, failed o expired — la posición en el ciclo de vida, nunca un veredicto. El resultado, cuando lo recibe, es result.decision |
step | Hasta dónde llegó el cliente: device_identification, document_front, document_back, selfie o done. device_identification es la identificación del navegador del cliente antes del documento, y aparece solo cuando la Inteligencia de dispositivo está habilitada |
deliveryMode | webhook o redirect — cómo le llega el desenlace de esta sesión, elegido al crearla |
result | El resultado normalizado completo una vez disponible, null antes de eso. Se actualiza en el mismo lugar cuando un analista decide |
expiresAt | El plazo de la sesión, el mismo valor que devolvió la respuesta de creación |
Las sesiones están estrictamente limitadas al tenant. El sessionId de otro tenant devuelve 404 — nunca una divulgación parcial.
Vencimiento de la Sesión
Una sesión que el cliente no termina a tiempo termina en expired. Su plazo se fija cuando usted la crea: las 48 horas del enlace más la hora que tiene para terminar un cliente que abrió el enlace al final — 49 horas después de la creación por defecto, devuelto como expiresAt en la respuesta de creación y en la lectura. Un cambio posterior en la vigencia del enlace nunca mueve el plazo de una sesión que ya existe.
| Cuándo | Qué pasa |
|---|---|
| 48 horas después de la creación | El enlace deja de abrirse. El cliente ve un mensaje de enlace vencido |
| Al vencer el plazo | La sesión termina en expired, en pocos minutos. Si el enlace se abre después del plazo, termina en el acto |
| Un envío sigue en evaluación al vencer el plazo | No vence mientras la evaluación se ejecuta — la sesión termina con su desenlace |
Todo lo que aún no se envió vence: un enlace que nunca se abrió, o un cliente que se detuvo a mitad de camino. Una sesión vencida no lleva decision ni evaluación, y se le entrega como cualquier otro desenlace — por webhook en modo webhook. Un cliente en un enlace vencido ve el mensaje de enlace vencido en lugar de su redirectUrl, así que en modo redirección le llega como una notificación de resultado cuando tiene un webhookUrl, y por la lectura en cualquier caso. Una vez que una sesión terminó, no se acepta ninguna captura más.
Las verificaciones server-to-server no tienen plazo y nunca vencen.
Próximos Pasos
- Validador de Número de Documento — verifique un número antes de llegar aquí
- Entrega del Widget — cómo guiar al cliente a través del flujo
- Recepción de Resultados — manejo de webhooks y redirecciones
- Sandbox y Datos de Prueba — números de documento reservados que dictan todo el resultado de una verificación
