Tiempo estimado: 45-60 minutos para configuración completa
¿Qué aprenderás en este manual?
Este manual te enseñará a configurar y usar el sistema de webhooks para recibir automáticamente una notificación cuando una verificación KYC se completa. No necesitas conocimientos técnicos avanzados - solo sigue los pasos.
Antes de Empezar - Lista de Verificación
Asegúrate de tener estos elementos listos:
- Servidor web con URL pública accesible (HTTPS obligatorio)
- Capacidad para recibir peticiones HTTP POST
- Conocimiento básico de APIs REST
- Acceso a tu plataforma JAAK configurada
- Editor de código o sistema para manejar peticiones HTTP
Índice de Contenidos
| Sección | Qué harás | Tiempo |
|---|---|---|
| Paso 1 | Entender qué son los webhooks | 5 min |
| Paso 2 | Configurar webhook en JAAK | 15 min |
| Paso 3 | Preparar endpoint para recibir datos | 20 min |
| Paso 4 | Probar funcionamiento | 10 min |
| Paso 5 | Interpretar respuestas | 15 min |
PASO 1: ¿Qué es un Webhook?
Concepto Básico
Un webhook es como un "mensajero automático" que JAAK envía a tu sistema cada vez que una verificación KYC se completa.
1.1 ¿Cómo funciona?
1. Cliente completa KYC en JAAK →
2. JAAK procesa la información →
3. JAAK envía una notificación a tu URL →
4. Tu sistema consulta los detalles en la URL incluida
1.2 Beneficios del Webhook
| ✅ Con Webhook | ❌ Sin Webhook |
|---|---|
| Recibes una notificación automática | Debes consultar manualmente cada resultado |
| Procesamiento en tiempo real | Demoras en obtener información |
| Actualizaciones inmediatas | Riesgo de perder notificaciones |
| Menor carga en tu sistema | Más llamadas API necesarias |
1.3 Información que Recibirás
El webhook te entrega una notificación compacta con los identificadores y el resultado global de la sesión. Los detalles completos (datos del usuario, documento, validaciones) los consultas después en la URL que viene dentro del mismo payload.
- Identificador de la sesión:
idyshortKey - Marcas de tiempo: Inicio, fin y duración
- Modo de validación: Cómo fue resuelta la sesión (automática, manual o pendiente de revisión)
- Etapa final (stage): Aprobado, rechazado, en revisión, etc.
- Scores: Puntuaciones numéricas por componente (liveness, documento, 1:1, etc.)
- URL de detalles: Enlace firmado al endpoint de JAAK con toda la información extendida
PASO 2: Configurar Webhook en JAAK
Objetivo
Configurar la URL donde JAAK enviará la notificación cuando se complete cada verificación.
Ruta de navegación
Dashboard Principal → Ajustes → Mi Compañía → Editar
2.1 Acceder a Configuración de Empresa
Paso 1: En el menú lateral ve hasta el botón de "Ajustes"
Paso 2: Haz clic en "Mi Compañía"
Paso 3: Presiona el botón "Editar" (ícono de lápiz)
2.2 Configurar Webhook en KYC Tradicional
En la sección "Configuración de Productos KYC" encontrarás:
📊 Campos de Webhook
| Campo | Descripción | Ejemplo | ¿Es obligatorio? |
|---|---|---|---|
| URL Webhook | Dirección donde JAAK enviará la notificación | https://tu-servidor.com/webhook/kyc | Recomendado |
| Auth Key | Clave de seguridad para autenticar llamadas | mi-clave-secreta-123 | Opcional |
2.3 Configurar URL Webhook
Formato Correcto de URL
✅ URLs Válidas:
https://mi-empresa.com/api/webhook/kyc
https://api.mi-empresa.com/kyc/results
https://servidor.mi-empresa.com:8080/webhook
❌ URLs Inválidas:
http://mi-empresa.com/webhook (no HTTPS)
mi-empresa.com/webhook (sin protocolo)
localhost:3000/webhook (no accesible públicamente)
Configurar Auth Key
La Auth Key es una clave secreta que JAAK incluirá en cada petición como header Api-AuthKey para que puedas verificar que el webhook realmente viene de JAAK. Si dejas el campo vacío, JAAK enviará el webhook sin header de autenticación — tu endpoint debe entonces aceptar la petición sin credenciales o validar por otro mecanismo (IP allowlist, firma, etc.).
Recomendaciones:
- Usa una combinación de letras, números y símbolos
- Mínimo 16 caracteres
- No uses información personal o predecible
- Guárdala en un lugar seguro
Ejemplo de Auth Key segura: JK2024-webhook-Auth-789XYZ
Información
Una vez guardada, la Auth Key queda encriptada en nuestros servidores y no se muestra de vuelta en el dashboard. Verás solo un indicador "Configurado". Para cambiarla presiona "Cambiar" y escribe la nueva clave; si dejas el campo vacío al guardar, la clave anterior se conserva.
2.4 Guardar Configuración
- Completa el campo URL Webhook (y opcionalmente Auth Key)
- Haz clic en "Guardar Cambios"
- Verás un mensaje de confirmación
- La configuración estará activa inmediatamente
PASO 3: Preparar Endpoint para Recibir Datos
Objetivo
Configurar tu servidor para recibir y procesar las peticiones HTTP POST de JAAK.
3.1 Especificaciones Técnicas
📡 Método HTTP y Headers
POST /tu-endpoint-webhook
Content-Type: application/json
Api-AuthKey: [TU-AUTH-KEY]
Importante
El header de autenticación se llama literalmente Api-AuthKey y la clave va como valor directo (sin prefijo Bearer). Si no configuraste Auth Key en el dashboard, este header no se envía.
Estructura de Datos que Recibirás
{
"id": "65f8a1b2c3d4e5f600000001",
"shortKey": "ABC123X",
"startedAt": "2026-01-15T10:27:36Z",
"endedAt": "2026-01-15T10:30:00Z",
"duration": "2.40m",
"validation": "AUTOMATIC",
"stage": "approved",
"scores": {
"liveness": 96.1,
"document": 98.2,
"oneToOne": 94.7,
"blacklist": 100.0,
"total": 95.5,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": true
},
"detailsURL": "https://api.jaak.ai/api/v1/kyc/session/65f8a1b2c3d4e5f600000001"
}
Información
El webhook no incluye datos personales del usuario (nombre, fecha de nacimiento, documento). Para obtener esa información consulta el endpoint indicado en detailsURL usando tu API Key de JAAK.
3.2 Implementación del Endpoint
Ejemplo en Python (Flask)
from flask import Flask, request, jsonify
app = Flask(__name__)
# Tu Auth Key configurada en JAAK (si la configuraste)
AUTH_KEY = "JK2024-webhook-Auth-789XYZ"
@app.route('/webhook/kyc', methods=['POST'])
def webhook_kyc():
# Verificar autenticación (solo si configuraste Auth Key en JAAK)
if AUTH_KEY:
received_key = request.headers.get('Api-AuthKey', '')
if received_key != AUTH_KEY:
return jsonify({"error": "Invalid auth key"}), 401
# Procesar datos
try:
data = request.get_json()
# Campos principales del webhook
session_id = data['id']
short_key = data['shortKey']
stage = data['stage'] # approved | rejected | in_review | ...
validation = data['validation'] # AUTOMATIC | MANUAL | NEED_REVIEW
details_url = data['detailsURL']
print(f"KYC Completado - Sesión: {session_id} ({short_key})")
print(f"Stage: {stage} | Validación: {validation}")
# Lógica de negocio
process_kyc_result(data)
# Para obtener datos personales, nombre, documento, etc.
# haz una petición autenticada a details_url
return jsonify({"received": True}), 200
except Exception as e:
print(f"Error procesando webhook: {e}")
return jsonify({"error": "Processing failed"}), 500
def process_kyc_result(data):
"""Tu lógica personalizada aquí"""
stage = data['stage']
if stage == "approved":
# Sesión aprobada - activar cuenta, enviar bienvenida, etc.
activate_user_account(data['id'])
elif stage == "rejected":
# Sesión rechazada - notificar, solicitar reintento, etc.
handle_rejection(data['id'])
elif stage == "in_review":
# Revisión manual requerida - notificar equipo de compliance
notify_manual_review(data['id'])
if __name__ == '__main__':
app.run(host='0.0.0.0', port=443, ssl_context='adhoc')
Ejemplo en Node.js (Express)
const express = require('express');
const app = express();
// Tu Auth Key configurada en JAAK (si la configuraste)
const AUTH_KEY = "JK2024-webhook-Auth-789XYZ";
app.use(express.json());
app.post('/webhook/kyc', (req, res) => {
// Verificar autenticación (solo si configuraste Auth Key en JAAK)
if (AUTH_KEY) {
const receivedKey = req.headers['api-authkey'] || '';
if (receivedKey !== AUTH_KEY) {
return res.status(401).json({ error: 'Invalid auth key' });
}
}
try {
const data = req.body;
const sessionId = data.id;
const shortKey = data.shortKey;
const stage = data.stage; // approved | rejected | in_review | ...
const validation = data.validation; // AUTOMATIC | MANUAL | NEED_REVIEW
const detailsURL = data.detailsURL;
console.log(`KYC Completado - Sesión: ${sessionId} (${shortKey})`);
console.log(`Stage: ${stage} | Validación: ${validation}`);
processKycResult(data);
// Para obtener datos personales, nombre, documento, etc.
// haz una petición autenticada a detailsURL
res.status(200).json({ received: true });
} catch (error) {
console.error('Error procesando webhook:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
function processKycResult(data) {
switch (data.stage) {
case 'approved':
activateUserAccount(data.id);
break;
case 'rejected':
handleRejection(data.id);
break;
case 'in_review':
notifyManualReview(data.id);
break;
}
}
app.listen(443, () => {
console.log('Webhook server running on port 443');
});
Ejemplo en PHP
<?php
header('Content-Type: application/json');
// Tu Auth Key configurada en JAAK (si la configuraste)
$AUTH_KEY = "JK2024-webhook-Auth-789XYZ";
// Verificar método HTTP
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
exit;
}
// Verificar autenticación (solo si configuraste Auth Key en JAAK)
if ($AUTH_KEY !== '') {
$receivedKey = $_SERVER['HTTP_API_AUTHKEY'] ?? '';
if ($receivedKey !== $AUTH_KEY) {
http_response_code(401);
echo json_encode(['error' => 'Invalid auth key']);
exit;
}
}
// Procesar datos
try {
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data) {
throw new Exception('Invalid JSON');
}
$sessionId = $data['id'];
$shortKey = $data['shortKey'];
$stage = $data['stage'];
$validation = $data['validation'];
$detailsURL = $data['detailsURL'];
error_log("KYC Completado - Sesión: $sessionId ($shortKey)");
error_log("Stage: $stage | Validación: $validation");
processKycResult($data);
http_response_code(200);
echo json_encode(['received' => true]);
} catch (Exception $e) {
error_log('Error procesando webhook: ' . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Processing failed']);
}
function processKycResult($data) {
switch ($data['stage']) {
case 'approved':
activateUserAccount($data['id']);
break;
case 'rejected':
handleRejection($data['id']);
break;
case 'in_review':
notifyManualReview($data['id']);
break;
}
}
?>
3.3 Requisitos de Respuesta
Respuesta Esperada
JAAK considera la entrega exitosa si recibe un status HTTP 2xx (idealmente 200). El body de la respuesta no es validado por JAAK, pero es buena práctica devolver un JSON confirmatorio:
HTTP/1.1 200 OK
Content-Type: application/json
{
"received": true
}
Timeout y Reintentos
- Timeout: JAAK espera un máximo de 10 segundos por tu respuesta. Si tu endpoint tarda más, la petición se aborta.
- Entrega fire-and-forget: JAAK envía el webhook una sola vez. Si tu servidor está caído o responde con error, no hay reintentos automáticos.
- Recomendaciones:
- Responde rápido (200 OK) antes de 10 segundos. Si tu lógica es pesada, encóla el evento y procésalo en background.
- Persiste el
id/shortKeyen tu lado apenas recibas el webhook para poder reconciliar. - Si necesitas re-obtener el resultado de una sesión, consulta el endpoint indicado en
detailsURLcon tu API Key.
PASO 4: Probar Funcionamiento
Objetivo
Verificar que tu webhook está funcionando correctamente con una sesión KYC de prueba.
4.1 Preparar Prueba
Checklist Pre-Prueba
- URL webhook configurada en JAAK
- Auth Key configurada en JAAK (opcional)
- Endpoint implementado y funcionando
- Servidor accesible desde internet (HTTPS)
- Logs habilitados para monitoreo
4.2 Crear Sesión de Prueba
-
Ir a JAAK Dashboard:
KYC → Sesiones → Crear nueva sesión -
Completar formulario:
- Nombre del contacto: "Test Webhook"
- Nombre del flujo: "Prueba-Webhook-001"
- URL redirección: Tu página de confirmación
- País de documentación: Tu país configurado
- Tipo de flujo: "KYC Tradicional"
-
Guardar y copiar URL: Se generará una URL como
https://kyc.sandbox.jaak.ai/session/ABC123X
4.3 Completar Verificación
- Abrir URL de sesión en navegador
- Seguir proceso KYC:
- Permitir acceso a cámara
- Capturar documento (frente y reverso)
- Capturar selfie/biometría
- Esperar procesamiento
- Monitorear logs de tu servidor durante el proceso
4.4 Verificar Recepción del Webhook
Qué Buscar en tus Logs
Si todo funciona correctamente, deberías ver:
[INFO] POST /webhook/kyc - Autenticación exitosa
[INFO] KYC Completado - Sesión: 65f8a1b2c3d4e5f600000001 (ABC123X)
[INFO] Stage: approved | Validación: AUTOMATIC
[INFO] Respuesta 200 enviada a JAAK
Si hay problemas, podrías ver:
[ERROR] POST /webhook/kyc - Api-AuthKey inválida
[ERROR] JSON malformado en webhook
[ERROR] Timeout procesando webhook
4.5 Validar en JAAK Dashboard
- Ir a:
KYC → Sesiones - Buscar tu sesión: "Prueba-Webhook-001"
- Verificar estado: Debe aparecer como completada
- Revisar logs: Si hay errores de webhook, aparecerán aquí
PASO 5: Interpretar Respuestas del Webhook
Objetivo
Entender completamente los datos que recibes en el webhook para implementar la lógica de negocio adecuada.
5.1 Campos del Webhook
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Identificador único de la sesión (ObjectId). Úsalo como llave en tu sistema. |
shortKey | string | Clave corta legible, la misma que aparece en el dashboard de JAAK. |
startedAt | string (ISO8601) | Fecha/hora de inicio de la sesión. |
endedAt | string (ISO8601) | Fecha/hora en que finalizó la sesión. |
duration | string | Duración total en minutos con formato "N.NNm" (ej: "2.40m"). |
validation | string (enum) | Modo de resolución: AUTOMATIC, MANUAL o NEED_REVIEW. (ver 5.2) |
stage | string (enum) | Etapa final de la sesión: approved, rejected, in_review, expired, etc. (ver 5.3) |
scores | object | Puntuaciones numéricas por componente (ver 5.4). |
detailsURL | string (URL) | Endpoint de JAAK donde consultar los detalles completos de la sesión. |
5.2 Valores de validation
| Valor | Significado |
|---|---|
AUTOMATIC | La sesión fue resuelta automáticamente por el motor de JAAK sin intervención humana. |
MANUAL | La sesión fue revisada y resuelta manualmente por un operador desde el dashboard de JAAK. |
NEED_REVIEW | La sesión quedó pendiente de revisión manual (el motor automático no pudo decidir). |
5.3 Valores de stage
Los valores más comunes que recibirás en una sesión finalizada son:
| Valor | Significado | Acción recomendada |
|---|---|---|
approved | ✅ Verificación exitosa | Activar cuenta, proceder con onboarding |
rejected | ❌ Verificación falló | Solicitar reintentar o documentos adicionales |
in_review | ⏳ Requiere revisión manual | Notificar equipo de compliance |
expired | ⌛ La sesión expiró sin completarse | Notificar al usuario, permitir reintentar |
lapsed | La sesión venció por inactividad | Notificar al usuario |
5.4 Campo scores
Puntuaciones numéricas por componente. Los valores por componente van de 0 a 100 (a mayor número, mayor confianza); el status resume el resultado global.
| Campo | Tipo | Descripción |
|---|---|---|
liveness | number | Score del chequeo de prueba de vida |
document | number | Score del chequeo del documento |
oneToOne | number | Score del match 1:1 (cara vs foto del documento) |
blacklist | number | Score del chequeo en listas restrictivas |
total | number | Score global combinado |
status | string | Resultado agregado: PASS, FAIL, NEED_REVIEW, ERROR, EXPIRED |
livenessPass | boolean | Si liveness pasó el umbral configurado en tu empresa |
documentPass | boolean | Si document pasó el umbral configurado |
oneToOnePass | boolean | Si oneToOne pasó el umbral configurado |
5.5 Consultar Detalles Extendidos
El webhook es intencionalmente compacto. Para obtener los datos personales extraídos (nombre, fecha de nacimiento, número de documento), imágenes capturadas o el desglose detallado por paso, consulta el endpoint en detailsURL con una petición autenticada usando tu API Key de JAAK.
curl -X GET "$DETAILS_URL" \
-H "Authorization: Bearer $JAAK_API_KEY"
5.6 Lógica de Negocio Recomendada
Flujo de Decisión
def process_kyc_webhook(data):
stage = data['stage']
validation = data['validation']
scores = data.get('scores', {}) or {}
total_score = scores.get('total', 0)
if stage == "approved":
if total_score >= 90:
# Alta confianza - aprobación automática
auto_approve_user(data)
elif total_score >= 70:
# Confianza media - aprobación con monitoreo
approve_with_monitoring(data)
else:
# Baja confianza - revisión manual interna
queue_for_manual_review(data)
elif stage == "rejected":
# Analizar qué componente falló
if scores.get('livenessPass') is False:
request_retry_with_instructions(data, "liveness")
elif scores.get('documentPass') is False:
request_different_document(data)
else:
manual_review_required(data)
elif stage == "in_review":
# Requiere revisión manual por parte de JAAK
notify_compliance_team(data)
elif stage in ("expired", "lapsed"):
# Sesión no completada a tiempo
send_retry_notification(data)
5.7 Casos Especiales
Situaciones a Considerar
Alta confianza global pero algún componente falló:
{
"stage": "approved",
"scores": {
"total": 95.0,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": false
}
}
Acción: Revisar manualmente - posible documento legítimo pero persona diferente.
Baja confianza aunque la sesión fue aprobada:
{
"stage": "approved",
"scores": {
"total": 65.0,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": true
}
}
Acción: Aprobar con monitoreo adicional - posible problema de calidad de imagen.
Sesión marcada como in_review:
{
"stage": "in_review",
"validation": "NEED_REVIEW"
}
Acción: Esperar a que un operador de JAAK o de tu equipo resuelva la sesión manualmente; recibirás un segundo webhook con el resultado final (approved o rejected).
Solución de Problemas Comunes
Problemas Frecuentes
Webhook no se recibe
| Problema | Causa Probable | Solución |
|---|---|---|
| No llegan peticiones | URL incorrecta en JAAK | Verificar configuración en "Mi Compañía" |
| Error 404/502 | Endpoint no existe o servidor caído | Verificar que tu servidor está funcionando |
| Error SSL/TLS | Certificado inválido | Usar HTTPS válido o renovar certificado |
| Timeout | Respuesta lenta del servidor | Responder en < 10s y procesar en background |
| Solo llega una vez | Fire-and-forget, sin retries | Consultar detailsURL para reconciliar |
Errores de autenticación
| Error | Descripción | Solución |
|---|---|---|
| "Missing Api-AuthKey" | Header Api-AuthKey no presente | Verificar que tu servidor lea el header correcto |
| "Invalid auth key" | El valor de Api-AuthKey no coincide | Revisar Auth Key en configuración JAAK |
| Error 401 constante | Auth Key mal configurada | Regenerar Auth Key en JAAK |
Importante
Asegúrate de que tu servidor lea el header Api-AuthKey (JAAK no utiliza Authorization: Bearer).
Problemas de procesamiento
| Síntoma | Causa | Fix |
|---|---|---|
| JSON malformado | Error al parsear datos | Añadir manejo de errores robusto |
| Datos faltantes | Cambios en estructura | Verificar campos antes de usar |
| Timeout al procesar | Lógica muy lenta | Mover procesamiento pesado a background |
Debugging Avanzado
Logs Detallados
import logging
import json
logging.basicConfig(level=logging.DEBUG)
@app.route('/webhook/kyc', methods=['POST'])
def webhook_kyc():
logger = logging.getLogger(__name__)
# Log headers completos
logger.debug(f"Headers recibidos: {dict(request.headers)}")
# Log body raw
raw_data = request.get_data()
logger.debug(f"Body raw: {raw_data}")
# Log IP origen
logger.debug(f"IP origen: {request.remote_addr}")
try:
data = request.get_json()
logger.info(f"Webhook procesado: {data.get('id')} ({data.get('shortKey')})")
# Log estructura de datos
logger.debug(f"Estructura completa: {json.dumps(data, indent=2)}")
return jsonify({"received": True}), 200
except Exception as e:
logger.error(f"Error procesando webhook: {str(e)}", exc_info=True)
return jsonify({"error": str(e)}), 500
Webhook de Prueba
Para probar tu endpoint sin hacer una sesión KYC completa:
curl -X POST https://tu-servidor.com/webhook/kyc \
-H "Content-Type: application/json" \
-H "Api-AuthKey: JK2024-webhook-Auth-789XYZ" \
-d '{
"id": "65f8a1b2c3d4e5f600000001",
"shortKey": "TEST123",
"startedAt": "2026-01-15T10:27:36Z",
"endedAt": "2026-01-15T10:30:00Z",
"duration": "2.40m",
"validation": "AUTOMATIC",
"stage": "approved",
"scores": {
"liveness": 96.1,
"document": 98.2,
"oneToOne": 94.7,
"blacklist": 100.0,
"total": 95.5,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": true
},
"detailsURL": "https://api.jaak.ai/api/v1/kyc/session/65f8a1b2c3d4e5f600000001"
}'
¿Necesitas Ayuda Adicional?
Cuándo contactar soporte técnico
- Errores de configuración que no puedes resolver
- Problemas de conectividad persistentes
- Cambios en la estructura de datos del webhook
- Preguntas sobre integración con sistemas específicos
Información a tener lista al contactar soporte
- URL de tu webhook configurada
- Logs de errores específicos con timestamps
- Ejemplo de petición que está fallando
- Configuración de ambiente (desarrollo/producción)
- ShortKey de sesión problemática (si aplica)
Recursos Adicionales
- Documentación API JAAK: Para consultar los detalles extendidos via
detailsURL - Postman Collection: Para probar endpoints manualmente
- SDK/Libraries: Si están disponibles para tu lenguaje
- Status Page: Para verificar el estado del servicio JAAK
Resumen Final
Has Aprendido A:
- Configurar URL webhook y Auth Key en JAAK
- Implementar endpoint para recibir la notificación
- Procesar y validar los campos del webhook
- Manejar diferentes valores de
stageyvalidation - Consultar
detailsURLpara obtener los datos extendidos - Solucionar problemas comunes
Próximos Pasos Recomendados
- Configurar monitoreo: Logs, alertas, métricas
- Implementar procesamiento en background: Para responder rápido en < 10s
- Añadir validaciones adicionales: Según tus reglas de negocio
- Documentar proceso: Para tu equipo y futuras referencias
- Probar en producción: Con volúmenes reales de transacciones
¡Felicidades! Ya tienes un sistema completo de webhooks para KYC funcionando. Tu sistema ahora puede recibir automáticamente las notificaciones y consultar los detalles de todas las verificaciones de identidad realizadas en JAAK.