Guías de Webhooks

📡 Webhooks de Capitalta - En Desarrollo

Los webhooks permiten que tu aplicación reciba notificaciones en tiempo real sobre eventos importantes en Capitalta. Esta guía describe cómo configurar y usar nuestros webhooks.


🔗 ¿Qué son los Webhooks?

Los webhooks son notificaciones HTTP que Capitalta envía a tu servidor cuando ocurren eventos específicos. En lugar de hacer polling constante a nuestra API, puedes recibir datos actualizados automáticamente.

Ventajas:


🎯 Eventos Disponibles

1. Créditos

credito.solicitado

{
  "evento": "credito.solicitado",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "id": "CR-2026-0001",
    "cliente_id": "CL-12345",
    "monto": 2500000,
    "plazo": 24,
    "tipo_garantia": "inmobiliaria",
    "estado": "en_revision"
  }
}

credito.aprobado

{
  "evento": "credito.aprobado",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "id": "CR-2026-0001",
    "monto_aprobado": 2500000,
    "tasa_anual": 12.5,
    "plazo": 24,
    "pago_mensual": 125000,
    "condiciones": {
      "garantia": "inmobiliaria",
      "seguro": true
    }
  }
}

credito.rechazado

{
  "evento": "credito.rechazado",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "id": "CR-2026-0001",
    "razones": [
      "Ingresos insuficientes",
      "Garantía con valor bajo"
    ],
    "recomendaciones": [
      "Reducir monto solicitado",
      "Proporcionar garantía adicional"
    ]
  }
}

2. Documentos

documento.recibido

{
  "evento": "documento.recibido",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "id": "DOC-2026-0001",
    "credito_id": "CR-2026-0001",
    "tipo": "identificacion",
    "estado": "validado",
    "validacion_ia": {
      "autenticidad": 95,
      "legibilidad": 98,
      "vigencia": true
    }
  }
}

documento.rechazado

{
  "evento": "documento.rechazado",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "id": "DOC-2026-0002",
    "credito_id": "CR-2026-0001",
    "tipo": "comprobante_domicilio",
    "razon": "Documento vencido",
    "recomendacion": "Subir documento con vigencia menor a 3 meses"
  }
}

3. Pagos

pago.realizado

{
  "evento": "pago.realizado",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "id": "PAG-2026-0001",
    "credito_id": "CR-2026-0001",
    "monto": 125000,
    "fecha_pago": "2026-01-01",
    "metodo": "transferencia_spei",
    "saldo_restante": 2375000
  }
}

pago.atrasado

{
  "evento": "pago.atrasado",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "credito_id": "CR-2026-0001",
    "dias_atraso": 5,
    "monto_pendiente": 125000,
    "intereses_moratorios": 2500
  }
}

4. Garantías

garantia.valorada

{
  "evento": "garantia.valorada",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "id": "GAR-2026-0001",
    "credito_id": "CR-2026-0001",
    "tipo": "inmobiliaria",
    "valor_avm": 5200000,
    "confianza_ia": 92,
    "fecha_valuacion": "2026-01-01"
  }
}

5. Construcción (Futuro)

proyecto.avance_actualizado

{
  "evento": "proyecto.avance_actualizado",
  "timestamp": "2026-01-01T00:00:00Z",
  "datos": {
    "proyecto_id": "PROY-2026-0001",
    "credito_id": "CR-2026-0001",
    "hito": "cimiento_completado",
    "porcentaje_avance": 15,
    "fotos": [
      "https://api.capitalta.mx/fotos/001.jpg",
      "https://api.capitalta.mx/fotos/002.jpg"
    ],
    "verificacion_ia": {
      "confianza": 95,
      "coincidencia_hito": true
    }
  }
}

🔧 Configuración de Webhooks

1. Registro del Webhook

POST /webhooks
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "url": "https://tu-servicio.com/webhook/capitalta",
  "eventos": [
    "credito.aprobado",
    "pago.realizado",
    "documento.recibido"
  ],
  "secret": "tu_secreto_seguro_aleatorio",
  "activo": true,
  "configuracion": {
    "reintentos": 3,
    "timeout": 30,
    "ssl_verification": true
  }
}

2. Verificación del Webhook

Cuando recibes un webhook, verifica la firma para confirmar que viene de Capitalta:

const crypto = require('crypto');

function verificarWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return signature === expectedSignature;
}

// Uso
const signature = req.headers['x-capitalta-signature'];
const payload = JSON.stringify(req.body);

if (verificarWebhook(payload, signature, 'tu_secreto_seguro_aleatorio')) {
  // Procesar webhook
  procesarEvento(req.body);
} else {
  // Rechazar - no es de Capitalta
  res.status(401).send('Firma inválida');
}

3. Respuesta Esperada

Tu endpoint debe responder con:

app.post('/webhook/capitalta', (req, res) => {
  try {
    // Verificar firma
    if (!verificarFirma(req)) {
      return res.status(401).send('Firma inválida');
    }
    
    // Procesar evento
    const evento = req.body;
    procesarEvento(evento);
    
    // Responder éxito
    res.status(200).json({ 
      recibido: true, 
      timestamp: new Date().toISOString() 
    });
    
  } catch (error) {
    console.error('Error procesando webhook:', error);
    res.status(500).send('Error interno');
  }
});

🔄 Reintentos y Conf fiabilidad

Estrategia de Reintentos

Si tu servidor no responde correctamente, Capitalta reintentará:

Headers de Reintentos

X-Capitalta-Retry-Count: 2
X-Capitalta-Retry-Reason: timeout

Manejo de Reintentos

function procesarEvento(evento) {
  // Verificar si ya procesamos este evento
  const eventoId = evento.datos.id;
  
  if (eventosProcesados.has(eventoId)) {
    console.log('Evento ya procesado:', eventoId);
    return;
  }
  
  // Marcar como procesado
  eventosProcesados.add(eventoId);
  
  // Procesar lógica
  switch(evento.evento) {
    case 'credito.aprobado':
      enviarEmailAprobacion(evento.datos);
      actualizarCRM(evento.datos);
      break;
      
    case 'pago.atrasado':
      iniciarProcesoCobranza(evento.datos);
      break;
  }
}

📊 Monitoreo y Logging

Logging de Webhooks

const webhookLog = {
  eventoId: evento.datos.id,
  timestamp: new Date().toISOString(),
  tipoEvento: evento.evento,
  httpStatus: 200,
  tiempoProcesamiento: Date.now() - inicio,
  retryCount: req.headers['x-capitalta-retry-count'] || 0
};

// Guardar en base de datos
await guardarWebhookLog(webhookLog);

Métricas Importantes


🛠️ Mejores Prácticas

1. Seguridad

// Siempre verificar la firma
if (!verificarFirma(req)) {
  return res.status(401).send('No autorizado');
}

// Usar HTTPS obligatoriamente
if (req.protocol !== 'https') {
  return res.status(400).send('HTTPS requerido');
}

2. Idempotencia

// Verificar si ya procesaste este evento
const eventoProcesado = await buscarEvento(evento.datos.id);
if (eventoProcesado) {
  return res.status(200).send('Ya procesado');
}

3. Manejo de Errores

try {
  await procesarEvento(evento);
  res.status(200).send('OK');
} catch (error) {
  console.error('Error:', error);
  // No responder 200 si hubo error real
  res.status(500).send('Error procesando');
}

4. Performance

// Responder rápidamente
res.status(200).send('OK');

// Procesar en background
setImmediate(() => {
  procesarEventoAsync(evento);
});

🧪 Testing

Webhook de Prueba

POST /webhooks/test
Authorization: Bearer {access_token}

{
  "url": "https://tu-servicio.com/webhook/test",
  "evento": "credito.aprobado",
  "datos": {
    "id": "TEST-001",
    "monto": 1000000
  }
}

Herramientas de Testing


📚 Ejemplos Completos

Node.js con Express

const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

const WEBHOOK_SECRET = process.env.CAPITALTA_WEBHOOK_SECRET;

// Verificar firma
function verificarFirma(req) {
  const signature = req.headers['x-capitalta-signature'];
  const payload = JSON.stringify(req.body);
  
  const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
    
  return signature === expectedSignature;
}

// Endpoint webhook
app.post('/webhook/capitalta', (req, res) => {
  // Verificar firma
  if (!verificarFirma(req)) {
    return res.status(401).send('Firma inválida');
  }
  
  const evento = req.body;
  
  // Procesar según tipo de evento
  switch(evento.evento) {
    case 'credito.aprobado':
      handleCreditoAprobado(evento.datos);
      break;
    case 'pago.realizado':
      handlePagoRealizado(evento.datos);
      break;
    case 'documento.recibido':
      handleDocumentoRecibido(evento.datos);
      break;
    default:
      console.log('Evento no manejado:', evento.evento);
  }
  
  res.status(200).json({ recibido: true });
});

app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

Python con Flask

import hashlib
import hmac
import json
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = os.environ.get('CAPITALTA_WEBHOOK_SECRET')

def verificar_firma(payload, signature):
    expected_signature = hmac.new(
        WEBHOOK_SECRET.encode('utf-8'),
        payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    
    return signature == expected_signature

@app.route('/webhook/capitalta', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Capitalta-Signature')
    payload = request.get_data(as_text=True)
    
    if not verificar_firma(payload, signature):
        abort(401)
    
    evento = request.json
    
    if evento['evento'] == 'credito.aprobado':
        procesar_credito_aprobado(evento['datos'])
    elif evento['evento'] == 'pago.realizado':
        procesar_pago_realizado(evento['datos'])
    
    return json.dumps({'recibido': True}), 200

if __name__ == '__main__':
    app.run(port=3000)

📋 Checklist de Configuración

Antes de Producción

En Producción


📞 Soporte Técnico

Canales de Soporte

Recursos

Horarios


Los webhooks de Capitalta están en desarrollo. Esta documentación se actualizará a medida que avance el proyecto.

Estado: En desarrollo
Lanzamiento estimado: Q4 2026
Última actualización: Noviembre 2024