Primeros Pasos
Esta guía te acompaña a través de una verificación de identidad completa en el sandbox de Inyo. Al finalizar habrás creado una sesión, verificado un documento y una selfie a través del widget alojado, y recibido un resultado firmado en tu propio endpoint.
Requisitos previos
- Credenciales de sandbox emitidas por Inyo durante el onboarding:
client_idyclient_secretpara el flujo client-credentials- Tu URL base de sandbox, y la confirmación de que tus rangos de IP de salida están en la lista de permitidos
- Un
webhook_secret— usado para verificar la firma de los resultados entregados
- Un endpoint de webhook, accesible públicamente por HTTPS, registrado con Inyo como tu
webhook_url. Durante el desarrollo funciona un túnel (ngrok, Cloudflare Tunnel); alternativamente usa la entrega por redirección y omite el webhook por completo. - Un teléfono con cámara para el widget. El acceso a la cámara requiere un contexto seguro, así que abre el widget por HTTPS — los navegadores de escritorio también funcionan.
- Un cliente REST (cURL, Postman o similar).
¿Aún no tienes credenciales? Ponte en contacto con nuestro equipo de ventas para solicitar acceso al sandbox.
Paso 1: Obtén un Token de Acceso
curl --request POST \
--url https://{FQDN}/oauth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data client_id=$KYC_CLIENT_ID \
--data client_secret=$KYC_CLIENT_SECRET
{
"access_token": "eyJhbGciOiJSUzI1NiIs…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "sessions verifications"
}
Guarda access_token y reutilízalo hasta que expire — consulta Autenticación para el manejo de renovación.
Paso 2: Crea una Sesión de Verificación
user_ref es tu propio identificador de la persona que se está verificando. Se devuelve en cada resultado, así que usa el identificador con el que tu sistema ya referencia a sus usuarios.
curl --request POST \
--url https://{FQDN}/v1/sessions \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"user_ref": "user-123",
"language": "en",
"delivery": { "mode": "webhook" }
}'
{
"session_id": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
"status": "pending",
"widget_url": "https://{FQDN}/verify/8Kd2mQ…"
}
Persiste ahora el session_id asociado a tu usuario — así es como correlacionarás el resultado entrante.
delivery.modeeswebhookpor defecto. Si no tienes unwebhook_urlconfigurado, esta llamada devuelve422; usa{"mode": "redirect", "redirect_url": "https://you.example/kyc-done"}en su lugar.
Paso 3: Envía al Cliente al Widget
Abre widget_url en el navegador del cliente o en un webview nativo, o entrégalo por SMS o correo electrónico. El enlace lleva un código de un solo uso y es válido por 48 horas.
El cliente selecciona un tipo de documento, fotografía el documento, se toma una selfie y ve el resultado. No escribes ningún código de cámara — consulta Entrega del Widget para detalles de webview y personalización de marca.
Paso 4: Recibe el Resultado Firmado
Cuando la verificación termina, Inyo envía un POST con el resultado a tu webhook_url con un encabezado X-Inyo-Signature:
POST /kyc-result HTTP/1.1 Content-Type: application/json X-Inyo-Signature: 4c1f9a…
{
"session_id": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
"user_ref": "user-123",
"status": "approved",
"auto_status": "approved",
"document": {
"type": "Passport",
"number": "A12345678",
"issuing_state": "USA",
"issuing_country": "USA",
"expiration_date": "2033-09-30"
},
"person": {
"first_name": "ALEX",
"last_name": "MORGAN",
"date_of_birth": "1988-03-04",
"nationality": "USA"
},
"checks": [
{ "name": "document_readable", "passed": true, "score": null, "detail": "all core fields extracted" },
{ "name": "mrz_valid", "passed": true, "score": null, "detail": "all check digits valid" },
{ "name": "document_not_expired", "passed": true, "score": null, "detail": "expiration_date 2033-09-30" },
{ "name": "face_match", "passed": true, "score": 98.7, "detail": "CompareFaces similarity vs threshold 90.0" }
],
"prefill_mismatches": [],
"provider": "inyo"
}
Verifica la firma antes de confiar en el payload. Es un HMAC-SHA256 de los bytes crudos del cuerpo de la solicitud, con tu webhook_secret como clave:
import crypto from "node:crypto";
const expected = crypto
.createHmac("sha256", process.env.KYC_WEBHOOK_SECRET)
.update(rawBody) // bytes crudos, antes de JSON.parse
.digest("hex");
const signature = req.headers["x-inyo-signature"];
const valid =
signature &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
Parsear el cuerpo y volver a serializarlo cambia los espacios en blanco y el orden de las claves y romperá la firma. Los detalles completos, incluido el modo de redirección, están en Recepción de Resultados.
Responde 2xx para confirmar la recepción. Inyo reintenta hasta tres veces con backoff, y luego se detiene.
Paso 5: Confirma del Lado del Servidor
GET /v1/sessions/{session_id} es el registro autoritativo. Úsalo para conciliar, para recuperar un webhook perdido, o siempre que necesites certeza en lugar de una notificación push:
curl --request GET \
--url https://{FQDN}/v1/sessions/$SESSION_ID \
--header "Authorization: Bearer $ACCESS_TOKEN"
{
"session_id": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
"user_ref": "user-123",
"status": "approved",
"step": "done",
"delivery_mode": "webhook",
"result": { "…": "the same normalized result" },
"created_at": "2026-07-31T14:02:11.481Z",
"updated_at": "2026-07-31T14:04:57.902Z"
}
Maneja Estos Tres Casos Antes de Salir a Producción
| Caso | Por qué importa | Dónde leer |
|---|---|---|
status es in_review | No es una respuesta final — un humano decide, y se te notifica después. Puede llegar por webhook y en una redirección. | Revisión Manual |
| Dos resultados para una sesión | Una decisión de analista o una reversión de control de calidad vuelve a entregar el resultado. Aplica el notified_at más alto, no la última llegada. | Recepción de Resultados |
| Un check falló pero quieres el detalle | passed es el resultado; los umbrales por tenant se citan en el detail de cada check. Nunca condiciones tu decisión al score de ai_authenticity. | Checks y Decisiones |
Próximos Pasos
| Página | Qué cubre |
|---|---|
| Sesiones de Verificación | Prefill, bloqueo del tipo de documento, verificaciones de datos, límites de captura |
| Entrega del Widget | Incrustación en webview, personalización de marca, localización |
| Verificación Servidor a Servidor | Usar tu propia interfaz de captura en lugar del widget |
| Configuración del Tenant | Umbrales, documentos y jurisdicciones aceptados |
| Sandbox y Datos de Prueba | Cómo provocar resultados approved, declined e in_review |
