talk to a human
Reading

Webhooks y Notificaciones de Eventos en Cobranza Automatizada: Guía de Integración 2026

Guía técnica completa de webhooks para plataformas de cobranza: eventos, payloads, seguridad, casos de uso y mejores prácticas de integración.

May 26, 2026 - 11 min read

|

by ed-escobar Co-Founder & CEO

Webhooks y Notificaciones de Eventos en Cobranza Automatizada: Guía de Integración 2026

Los webhooks son el mecanismo técnico que permite a las plataformas de cobranza automatizada integrarse profundamente con el ecosistema tecnológico de una empresa. A diferencia de las integraciones tradicionales que requieren polling constante ("¿hay algo nuevo?", "¿hay algo nuevo?"), los webhooks funcionan con un modelo push: la plataforma de cobranza notifica a tus sistemas en tiempo real cuando ocurren eventos relevantes.

En Kleva, procesamos miles de eventos diarios —pagos recibidos, promesas de pago obtenidas, disputas detectadas, casos escalados— y nuestros clientes necesitan recibir estas notificaciones inmediatamente para actualizar sus ERPs, CRMs, dashboards ejecutivos y sistemas de BI sin latencia ni complejidad de integración.

Esta guía técnica profundiza en cómo funcionan los webhooks en contextos de cobranza, qué eventos son esenciales, cómo diseñar payloads efectivos, implementar seguridad robusta y manejar casos edge que pueden romper integraciones.

¿Qué es un Webhook y Por Qué Importa en Cobranza?

Un webhook es un HTTP callback: un POST request que una aplicación envía a una URL definida cuando ocurre un evento específico. En el contexto de cobranza automatizada:

Escenario tradicional sin webhooks:

  • Tu ERP debe consultar la plataforma de cobranza cada 15 minutos: "¿Hay pagos nuevos?"
  • Si hay 1,000 empresas usando la plataforma, eso es 96,000 requests diarios solo para polling
  • Latencia de hasta 15 minutos entre que ocurre el evento y tu sistema lo detecta
  • Complejidad de implementar lógica de sincronización y manejo de estado

Escenario con webhooks:

  • Cuando un deudor paga, Kleva inmediatamente envía POST request a tu endpoint configurado
  • Tu sistema recibe notificación en

Tu sistema recibe notificación en

  • Cero polling, cero latencia, cero complejidad de sincronización

Eventos Críticos en Plataformas de Cobranza

Una plataforma robusta de cobranza debe emitir webhooks para estos eventos:

1. Eventos de Pago

payment.received: Se recibió un pago


{
"event": "payment.received",
"timestamp": "2026-05-26T14:23:45Z",
"data": {
"payment_id": "pmt_abc123",
"invoice_id": "inv_12345",
"debtor_id": "deb_98765",
"amount": 1500.00,
"currency": "MXN",
"payment_method": "credit_card",
"transaction_id": "txn_stripe_xyz789",
"status": "confirmed",
"paid_at": "2026-05-26T14:23:30Z"
}
}

payment.failed: Intento de pago falló (tarjeta declinada, fondos insuficientes)

payment.refunded: Un pago fue revertido

2. Eventos de Promise to Pay

ptp.created: Se obtuvo una promesa de pago


{
"event": "ptp.created",
"timestamp": "2026-05-26T10:15:22Z",
"data": {
"ptp_id": "ptp_def456",
"invoice_id": "inv_12345",
"debtor_id": "deb_98765",
"promised_amount": 2000.00,
"promised_date": "2026-06-01",
"obtained_by": "voice_agent_001",
"confidence_score": 0.85,
"recording_url": "https://recordings.kleva.co/call_789.mp3",
"notes": "Cliente confirma pago el 1 de junio, día de quincena"
}
}

ptp.fulfilled: Promesa de pago fue cumplida

ptp.broken: Promesa de pago no fue cumplida en la fecha acordada

3. Eventos de Contacto

contact.completed: Se completó un intento de contacto (exitoso o no)


{
"event": "contact.completed",
"timestamp": "2026-05-26T11:30:10Z",
"data": {
"contact_id": "cnt_ghi789",
"invoice_id": "inv_12345",
"debtor_id": "deb_98765",
"channel": "voice",
"status": "contacted",
"duration_seconds": 185,
"outcome": "promise_to_pay_obtained",
"agent_type": "ai_voice_agent",
"transcript": "[Transcripción completa...]",
"sentiment_score": 0.65,
"next_action": "wait_for_payment"
}
}

contact.failed: No se pudo establecer contacto (no contesta, número inválido)

4. Eventos de Escalamiento

case.escalated: Caso fue escalado a gestor humano


{
"event": "case.escalated",
"timestamp": "2026-05-26T13:45:00Z",
"data": {
"case_id": "case_jkl012",
"invoice_id": "inv_12345",
"debtor_id": "deb_98765",
"escalation_reason": "dispute_detected",
"priority": "high",
"assigned_to": "agent_maria_lopez",
"previous_attempts": 3,
"context_summary": "Cliente reporta producto defectuoso, requiere investigación",
"estimated_resolution_time": "2026-05-27T10:00:00Z"
}
}

case.resolved: Caso escalado fue resuelto

5. Eventos de Disputa

dispute.created: Se detectó una disputa


{
"event": "dispute.created",
"timestamp": "2026-05-26T15:00:00Z",
"data": {
"dispute_id": "dsp_mno345",
"invoice_id": "inv_12345",
"debtor_id": "deb_98765",
"dispute_type": "product_quality",
"description": "Cliente reporta que producto llegó dañado",
"reported_by": "voice_agent_001",
"requires_action_from": ["sales_team", "quality_team"],
"status": "pending_investigation"
}
}

dispute.resolved: Disputa fue resuelta (a favor de empresa o cliente)

6. Eventos de Ciclo de Vida de Cuenta

account.sent_to_collections: Cuenta fue enviada a cobranza

account.closed: Cuenta fue cerrada (pagada completamente o castigada)

account.written_off: Cuenta fue castigada como incobrable

Diseño de Payloads: Mejores Prácticas

Un payload de webhook bien diseñado sigue estos principios:

1. Estructura Consistente

Todos los webhooks deben tener estructura base común:


{
"event": "nombre.del.evento",
"timestamp": "ISO 8601 timestamp",
"webhook_id": "id único de este webhook",
"data": { /* datos específicos del evento */ },
"metadata": {
"environment": "production",
"version": "v2"
}
}

2. Idempotencia

Incluir webhook_id único permite al receptor deduplicar webhooks en caso de reenvíos:


# Código del receptor (Python)
if Webhook.objects.filter(webhook_id=payload['webhook_id']).exists():
return HttpResponse(status=200) # Ya procesado, ignorar

# Procesar webhook...
Webhook.objects.create(webhook_id=payload['webhook_id'], processed=True)

3. Referencias Completas

Incluir todos los IDs relevantes facilita joins en base de datos del receptor:


"data": {
"payment_id": "pmt_abc123",
"invoice_id": "inv_12345", // Referencia a factura
"debtor_id": "deb_98765", // Referencia a deudor
"campaign_id": "cmp_555", // Referencia a campaña
"agent_id": "agent_001" // Referencia a agente que gestionó
}

4. Timestamps en ISO 8601

Siempre UTC, siempre con timezone:


"timestamp": "2026-05-26T14:23:45Z" // Correcto
"timestamp": "2026-05-26 14:23:45" // Incorrecto (ambiguo)

Seguridad de Webhooks

Los webhooks son endpoints públicos expuestos a internet. La seguridad es crítica:

1. Validación de Firma HMAC

Kleva firma cada webhook con HMAC-SHA256:

Lado emisor (Kleva):


import hmac
import hashlib

payload = json.dumps(webhook_data)
secret = "tu_clave_secreta_compartida"
signature = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()

headers = {
'X-Kleva-Signature': signature,
'Content-Type': 'application/json'
}

Lado receptor (tu servidor):


import hmac
import hashlib

def verify_webhook(request):
received_signature = request.headers.get('X-Kleva-Signature')
payload = request.body
secret = os.environ['KLEVA_WEBHOOK_SECRET']

expected_signature = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()

if not hmac.compare_digest(received_signature, expected_signature):
raise SecurityError("Webhook signature invalid")

return json.loads(payload)

2. Whitelist de IPs

Configurar firewall para aceptar webhooks solo desde IPs de la plataforma:


# Nginx config
location /webhooks/kleva {
allow 52.14.98.123; # IP de Kleva 1
allow 52.14.98.124; # IP de Kleva 2
deny all;
proxy_pass http://localhost:8000;
}

3. HTTPS Obligatorio

La plataforma debe rechazar URLs de webhook que no sean HTTPS:


http://example.com/webhook ❌ Rechazado
https://example.com/webhook ✅ Aceptado

4. Rate Limiting

Proteger endpoint de webhook contra ataques de denegación de servicio:


# Django + django-ratelimit
from django_ratelimit.decorators import ratelimit

@ratelimit(key='ip', rate='100/m', method='POST')
def kleva_webhook_handler(request):
# Procesar webhook...

Manejo de Reintentos y Fallos

Los endpoints de webhook pueden fallar por múltiples razones: servidor caído, deploy en curso, error en código receptor. Una plataforma robusta debe implementar estrategia de reintentos:

Estrategia de Backoff Exponencial

Kleva reintenta webhooks fallidos con este schedule:

  • Intento 1: Inmediato
  • Intento 2: +1 minuto
  • Intento 3: +5 minutos
  • Intento 4: +15 minutos
  • Intento 5: +1 hora
  • Intento 6: +6 horas
  • Intento 7: +24 horas

Después de 7 intentos fallidos, el webhook se marca como "failed" y se notifica al administrador.

Códigos HTTP y Comportamiento

Código HTTPSignificadoAcción de Kleva

200-299ÉxitoMarcar como entregado, no reintentar

400, 404, 422Error del cliente (URL mala, payload inválido)NO reintentar, notificar administrador

401, 403Error de autenticaciónNO reintentar, verificar configuración

500-599Error del servidorReintentar con backoff exponencial

Timeout (>30s)Servidor no respondeReintentar con backoff exponencial

Endpoint de Respuesta del Receptor

Tu endpoint debe responder apropiadamente:


@app.route('/webhooks/kleva', methods=['POST'])
def handle_kleva_webhook():
try:
# 1. Verificar firma
verify_webhook_signature(request)

# 2. Parsear payload
payload = request.get_json()

# 3. Procesar de forma asíncrona (no bloquear respuesta)
process_webhook_async.delay(payload)

# 4. Responder inmediatamente con 200
return jsonify({"status": "received"}), 200

except SignatureError:
return jsonify({"error": "Invalid signature"}), 401
except Exception as e:
logger.error(f"Webhook processing error: {e}")
return jsonify({"error": "Internal error"}), 500

Importante: Responder con 200 inmediatamente, procesar asíncronamente. No hacer procesamiento pesado antes de responder.

Casos de Uso: Integraciones Reales

Caso 1: Sincronización con ERP (SAP, Oracle, Dynamics)

Objetivo: Actualizar status de factura en ERP cuando ocurre pago o promesa de pago.

Flujo:

  1. Deudor paga $2,500 MXN en Kleva
  2. Kleva emite webhook payment.received
  3. Middleware recibe webhook, extrae invoice_id
  4. Middleware consulta ERP para obtener ID interno de factura
  5. Middleware actualiza factura en ERP: status = "PAID", payment_date = timestamp
  6. Middleware registra transacción en journal contable

Código de ejemplo:


def process_payment_webhook(payload):
invoice_id = payload['data']['invoice_id']
amount = payload['data']['amount']
paid_at = payload['data']['paid_at']

# Mapear ID de Kleva a ID de SAP
sap_invoice = InvoiceMapping.objects.get(kleva_id=invoice_id)

# Actualizar en SAP
sap_client.update_invoice(
invoice_number=sap_invoice.sap_number,
status='PAID',
payment_amount=amount,
payment_date=paid_at
)

# Registrar en journal
sap_client.create_journal_entry(
account='1105', # Cuentas por cobrar
debit=amount,
description=f'Pago recibido via Kleva - {invoice_id}'
)

Caso 2: Alertas en Slack/Teams para Equipo de Cobranza

Objetivo: Notificar equipo inmediatamente cuando ocurren eventos críticos.

Eventos a notificar:

  • payment.received (montos >$10,000 USD)
  • case.escalated (todos)
  • dispute.created (todos)
  • ptp.broken (promesas >$5,000 USD)

Código de ejemplo:


def notify_team_via_slack(payload):
event = payload['event']

if event == 'payment.received' and payload['data']['amount'] > 10000:
message = f"💰 Pago grande recibido: ${payload['data']['amount']} USD de {payload['data']['debtor_id']}"
channel = "#collections-wins"

elif event == 'case.escalated':
message = f"⚠️ Caso escalado: {payload['data']['case_id']} - Razón: {payload['data']['escalation_reason']}"
channel = "#collections-escalations"

elif event == 'dispute.created':
message = f"🚨 Disputa creada: {payload['data']['dispute_type']} - {payload['data']['description']}"
channel = "#collections-disputes"

slack_client.post_message(channel=channel, text=message)

Caso 3: Dashboard Ejecutivo en Tiempo Real

Objetivo: Actualizar dashboard de métricas sin polling.

Flujo:

  1. Webhooks actualizan base de datos local (PostgreSQL/MySQL)
  2. Base de datos dispara notificación a WebSocket server
  3. WebSocket empuja actualización a dashboard en browser del CFO
  4. Dashboard se actualiza en tiempo real sin refresh

Arquitectura:


Kleva webhook → Flask endpoint → PostgreSQL →
PostgreSQL NOTIFY → WebSocket server → Dashboard browser

Caso 4: Automatización con Zapier/Make/n8n

Objetivo: Integrar con cientos de apps sin código custom.

Ejemplos:

  • payment.received → Crear fila en Google Sheets de reporte diario
  • ptp.created → Crear tarea en Asana/Trello para seguimiento
  • dispute.created → Enviar email al gerente de ventas
  • case.escalated → Crear ticket en Zendesk/Freshdesk

Monitoreo y Debugging de Webhooks

Una plataforma profesional debe ofrecer herramientas de debugging:

Panel de Webhooks en Kleva

  • Log completo: Todos los webhooks enviados, timestamps, status codes de respuesta
  • Payload inspector: Ver payload exacto de cualquier webhook enviado
  • Replay manual: Reenviar webhook manualmente para testing
  • Métricas: Tasa de éxito, latencia promedio, errores frecuentes
  • Alertas: Notificar si tasa de fallo supera umbral (ej: >5%)

Testing de Endpoints Locales

Durante desarrollo, usar herramientas como ngrok para exponer localhost:


# Terminal 1: Iniciar servidor local
python manage.py runserver

# Terminal 2: Exponer con ngrok
ngrok http 8000

# Configurar URL de webhook en Kleva:
https://abc123.ngrok.io/webhooks/kleva

Versionado de Webhooks

Los webhooks evolucionan. Una plataforma madura debe soportar múltiples versiones simultáneamente:

Estrategia de Versionado


# Versión en header HTTP
X-Kleva-Webhook-Version: v2

# O en el payload
{
"event": "payment.received",
"version": "v2",
"data": { ... }
}

Política de deprecación:

  1. Lanzar v2 con nuevas features
  2. Mantener v1 funcionando por 12 meses
  3. A los 6 meses, marcar v1 como deprecated y notificar clientes
  4. A los 12 meses, descontinuar v1

Mejores Prácticas de Implementación

1. Procesar Asíncronamente

NUNCA hacer procesamiento pesado en el endpoint de webhook. Usar queue:


# Mal ❌
@app.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.get_json()
update_erp(payload) # Puede tardar 5-10 segundos
send_email(payload) # Puede tardar 2-3 segundos
return {"status": "ok"}, 200 # Kleva esperó 8 segundos

# Bien ✅
@app.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.get_json()
redis_queue.enqueue(process_webhook, payload)
return {"status": "received"}, 200 # Respuesta en

2. Idempotencia en Procesamiento

Siempre verificar si webhook ya fue procesado:


def process_webhook(payload):
webhook_id = payload['webhook_id']

# Usar transaction atómica
with transaction.atomic():
# Intentar crear registro
webhook_log, created = WebhookLog.objects.get_or_create(
webhook_id=webhook_id,
defaults={'payload': payload, 'processed': False}
)

if not created:
# Ya existe, ya fue procesado
return

# Procesar...
update_invoice(payload['data']['invoice_id'])

# Marcar como procesado
webhook_log.processed = True
webhook_log.save()

3. Logging Exhaustivo

Registrar todo para debugging posterior:


import logging

logger = logging.getLogger('webhooks')

def handle_webhook(request):
# Log request completo
logger.info(f"Webhook received: {request.headers}")
logger.info(f"Payload: {request.body}")

try:
result = process_webhook(request.get_json())
logger.info(f"Webhook processed successfully: {result}")
return {"status": "ok"}, 200
except Exception as e:
logger.error(f"Webhook processing failed: {e}", exc_info=True)
return {"status": "error"}, 500

4. Monitoreo de Salud del Endpoint

Implementar health check que la plataforma puede verificar:


@app.route('/webhooks/health', methods=['GET'])
def webhook_health():
# Verificar conectividad a DB
db.session.execute('SELECT 1')

# Verificar queue funcionando
queue_status = redis_queue.get_status()

return {
"status": "healthy",
"timestamp": datetime.utcnow().isoformat(),
"queue_size": queue_status['size']
}, 200

Conclusión

Los webhooks son la columna vertebral de integraciones modernas en plataformas de cobranza automatizada. Implementarlos correctamente —con seguridad robusta, manejo de reintentos, idempotencia y monitoreo— permite que sistemas de cobranza como Kleva se integren profundamente en el ecosistema tecnológico empresarial sin complejidad ni latencia.

Las empresas que aprovechan webhooks para sincronizar ERPs, actualizar dashboards en tiempo real, automatizar workflows y alertar equipos logran operaciones de cobranza verdaderamente unificadas donde todos los sistemas están sincronizados en tiempo real, eliminando silos de información y maximizando eficiencia operacional.

La diferencia entre una integración básica vía API polling y una integración avanzada vía webhooks es la diferencia entre actualización cada 15 minutos versus actualización en menos de 1 segundo —y en cobranza, esa diferencia puede significar capturar un pago antes de que el deudor cambie de opinión.

Talk to a human

No bots, no endless forms. Fill in your details and someone from our team will reach out.

Your information is secure and will only be used for scheduling purposes

Reach us out

Reach out directly to our team*

  • Email hi@kleva.co
  • WhatsApp +1 704-816-9059
  • Office Miami, Florida