Webhooks: Cargas firmadas y reintentos

Backend2026-10-08TryQuickToolBox

Acabas de integrar una pasarela de pago usando webhooks. Todo funciona en las pruebas, pero en producción, a veces los eventos se pierden o recibes notificaciones duplicadas que causan cargos dobles. La causa raíz suele estar en cómo manejas las cargas firmadas y los reintentos. Este artículo explica la mecánica de los webhooks y proporciona pasos prácticos para construir una integración robusta y segura.

¿Qué son los webhooks?

Los webhooks son callbacks HTTP definidos por el usuario. Cuando ocurre un evento en un sistema de origen (por ejemplo, se procesa un pago), envía una solicitud HTTP POST a una URL que especifiques, con los datos del evento. A diferencia del polling, los webhooks envían datos casi en tiempo real, reduciendo la latencia y la carga del servidor.

Sin embargo, los webhooks presentan desafíos: verificar la autenticidad, manejar fallos y garantizar un procesamiento exactamente una vez. Abordemos cada uno.

Cargas firmadas: verificar la autenticidad

Dado que los endpoints de webhook son accesibles públicamente, cualquiera podría enviar solicitudes falsas. Para evitarlo, los proveedores firman la carga con una clave secreta. Tú verificas la firma para asegurar que la solicitud es genuina.

Cómo funcionan las firmas HMAC

La mayoría de los proveedores usan HMAC (Hash-based Message Authentication Code) con SHA-256. El proveedor calcula una firma usando el cuerpo de la solicitud y un secreto compartido, y luego la incluye en una cabecera (por ejemplo, X-Signature). Tú recalculas la firma en tu lado y comparas.

Ejemplo en Python:

import hmac
import hashlib

def verify_signature(payload, secret, received_signature):
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_signature)

Importante: Usa el cuerpo de la solicitud sin procesar, no el JSON parseado, ya que el parseo puede alterar los espacios en blanco y romper la firma.

Errores comunes

Reintentos: manejar fallos con gracia

Tu endpoint podría estar temporalmente caído, o problemas de red podrían causar fallos. Los sistemas de webhooks fiables reintentan las entregas fallidas con retroceso exponencial.

Estrategias de reintento

Los proveedores normalmente reintentan en respuestas no-2xx o timeouts. Patrones comunes:

EstrategiaDescripciónEjemplo
Intervalo fijoReintentar cada N segundosCada 30s, hasta 5 veces
Retroceso exponencialDuplicar el retraso en cada intento1s, 2s, 4s, 8s...
Exponencial con jitterAñadir aleatoriedad para evitar el efecto estampida1s ± 0.5s, 2s ± 1s...

Como receptor, no puedes controlar la política de reintentos del emisor, pero puedes diseñar tu endpoint para que sea resiliente.

Mejores prácticas para receptores

  1. Responde rápido: Devuelve 2xx en unos segundos. Deriva el procesamiento a un trabajo en segundo plano.
  2. Sé idempotente: Usa una clave de idempotencia del payload para evitar procesamiento duplicado.
  3. Registra todo: Almacena los webhooks entrantes para depuración y reproducción.
  4. Monitorea fallos: Configura alertas para fallos repetidos.

Implementar idempotencia

Los duplicados ocurren: el emisor podría reintentar porque tu respuesta fue lenta, o podrías procesar accidentalmente el mismo evento dos veces. La idempotencia asegura que procesar un evento múltiples veces tenga el mismo efecto que una vez.

Usa un ID de evento único (a menudo proporcionado en el payload o cabeceras) y guárdalo en una base de datos con una restricción única. Antes de procesar, verifica si el ID existe; si es así, omite.

def process_event(event_id, data):
    if EventLog.exists(event_id):
        return  # ya procesado
    EventLog.create(event_id)
    # procesar datos...

Para sistemas de alto rendimiento, usa un bloqueo distribuido o una transacción de base de datos para evitar condiciones de carrera.

Consideraciones de seguridad

Además de la verificación de firma, considera:

Probar webhooks localmente

Durante el desarrollo, necesitas una URL pública para recibir webhooks. Herramientas como ngrok o localtunnel exponen tu servidor local. Alternativamente, muchos proveedores ofrecen una CLI para reenviar eventos a tu localhost.

Simula fallos para probar el manejo de reintentos: devuelve errores 500 intencionalmente y observa el patrón de reintento del proveedor.

Preguntas frecuentes

¿Cómo verifico una firma de webhook?

Usa HMAC con el secreto compartido. Calcula el hash del cuerpo de la solicitud sin procesar y compáralo con la cabecera de firma usando una función de comparación en tiempo constante.

¿Qué debo hacer si recibo webhooks duplicados?

Implementa idempotencia almacenando IDs de eventos. Verifica si el evento ya ha sido procesado antes de ejecutar la lógica de negocio.

¿Puedo confiar solo en los reintentos de webhooks para la fiabilidad?

No. Los reintentos ayudan pero no pueden garantizar la entrega. Para eventos críticos, combina webhooks con un respaldo de polling o una cola de mensajes que persista eventos.

Al depurar cargas de webhooks, es posible que necesites inspeccionar datos JSON. Usa nuestro JSON Formatter para formatear y validar cargas rápidamente.