Inyo

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_id y client_secret para 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.mode es webhook por defecto. Si no tienes un webhook_url configurado, esta llamada devuelve 422; 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

CasoPor qué importaDónde leer
status es in_reviewNo 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ónUna 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 detallepassed 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áginaQué cubre
Sesiones de VerificaciónPrefill, bloqueo del tipo de documento, verificaciones de datos, límites de captura
Entrega del WidgetIncrustación en webview, personalización de marca, localización
Verificación Servidor a ServidorUsar tu propia interfaz de captura en lugar del widget
Configuración del TenantUmbrales, documentos y jurisdicciones aceptados
Sandbox y Datos de PruebaCómo provocar resultados approved, declined e in_review