Volver a documentación
Guía30 min

Flujo de onboarding KYC

Implementa un flujo completo de verificación de identidad con captura de documentos, prueba de vida y comparación facial.

Visión general

El flujo de onboarding KYC de JAAK consiste en los siguientes pasos:

1
Captura de documento
2
Validación OCR
3
Prueba de vida
4
Comparación facial

1. Crear sesión de verificación

Configura el flujo de verificación según tus necesidades:

POST /v1/verifications
const session = await jaak.verification.create({
  type: 'full_kyc',
  config: {
    // Tipos de documento aceptados
    documentTypes: ['ine', 'ine_reverso', 'passport'],

    // Habilitar prueba de vida pasiva
    livenessCheck: {
      enabled: true,
      type: 'passive' // 'passive' o 'active'
    },

    // Habilitar comparación facial
    faceMatch: {
      enabled: true,
      threshold: 0.85 // Umbral de similitud (0-1)
    },

    // Consultar bases oficiales
    officialSources: {
      ine: true,    // Validar en padrón INE
      renapo: true, // Validar CURP
      sat: false    // Validar RFC
    },

    // Opciones de captura
    capture: {
      allowUpload: false,  // Solo permitir cámara
      quality: 'high',
      retries: 3
    }
  },

  // Datos del usuario (opcional)
  userData: {
    email: 'usuario@ejemplo.com',
    phone: '+525512345678'
  },

  // Metadatos para tu sistema
  metadata: {
    userId: 'usr_abc123',
    applicationId: 'app_xyz789'
  },

  // URL de redirección al terminar
  redirectUrl: 'https://tuapp.com/onboarding/completado',

  // Webhook para notificaciones
  webhookUrl: 'https://tuapp.com/webhooks/jaak'
});

2. Redirigir al usuario

Redirige al usuario a la URL de verificación. JAAK se encarga de toda la experiencia:

// En tu frontend
window.location.href = session.verificationUrl;

// O en React/Next.js
import { useRouter } from 'next/navigation';

const router = useRouter();
router.push(session.verificationUrl);

Tip: También puedes embeber el flujo en un iframe o usar nuestro SDK de Web para una experiencia integrada.

3. Procesar resultados

Recibe el resultado de la verificación vía webhook:

Webhook: verification.completed
{
  "event": "verification.completed",
  "timestamp": "2025-01-09T10:30:00Z",
  "data": {
    "sessionId": "ses_abc123",
    "status": "approved", // approved, rejected, pending_review

    "document": {
      "type": "ine",
      "number": "XXXX1234567890",
      "name": "JUAN PEREZ GARCIA",
      "birthDate": "1990-05-15",
      "address": "CALLE EJEMPLO 123, CDMX",
      "curp": "PEGJ900515HDFRRL09",
      "claveElector": "PRGRJN90051509H800",
      "validUntil": "2029-12-31",
      "isValid": true,
      "securityFeatures": {
        "hologram": true,
        "microprint": true,
        "uvElements": true
      }
    },

    "biometrics": {
      "livenessScore": 0.98,
      "livenessResult": "live",
      "faceMatchScore": 0.95,
      "faceMatchResult": "match"
    },

    "officialSources": {
      "ine": {
        "status": "valid",
        "matchedFields": ["name", "curp", "photo"]
      },
      "renapo": {
        "status": "valid",
        "curpValid": true
      }
    },

    "evidence": {
      "documentFront": "https://evidence.jaak.ai/doc_front_xxx.jpg",
      "documentBack": "https://evidence.jaak.ai/doc_back_xxx.jpg",
      "selfie": "https://evidence.jaak.ai/selfie_xxx.jpg",
      "livenessVideo": "https://evidence.jaak.ai/liveness_xxx.mp4"
    },

    "metadata": {
      "userId": "usr_abc123",
      "applicationId": "app_xyz789"
    }
  }
}

4. Manejar los resultados

app.post('/webhooks/jaak', async (req, res) => {
  const { event, data } = req.body;

  if (event === 'verification.completed') {
    const { sessionId, status, document, biometrics } = data;

    switch (status) {
      case 'approved':
        // Verificación exitosa
        await updateUserStatus(data.metadata.userId, 'verified');
        await saveVerificationData(sessionId, document);
        await sendWelcomeEmail(document.name);
        break;

      case 'rejected':
        // Verificación rechazada
        await updateUserStatus(data.metadata.userId, 'rejected');
        await notifyRejection(data.metadata.userId, data.rejectionReason);
        break;

      case 'pending_review':
        // Requiere revisión manual
        await createReviewTask(sessionId, data);
        break;
    }
  }

  res.status(200).send('OK');
});

Mejores prácticas

  • Siempre valida la firma HMAC del webhook antes de procesar
  • Guarda el sessionId para consultas futuras y auditorías
  • Implementa idempotencia en tu endpoint de webhook
  • Usa el ambiente sandbox para pruebas antes de producción