Webhooks explicados: cargas firmadas y reintentos

Backend2026-11-06TryQuickToolBox

Has integrado una pasarela de pago o un servicio de CI/CD, y ahora necesitas recibir eventos en tiempo real. Los webhooks son la solución estándar, pero conllevan dos grandes desafíos: verificar que la solicitud realmente proviene del remitente esperado y manejar fallos cuando tu endpoint está caído o lento. Este artículo explica cómo implementar cargas de webhook firmadas y una lógica de reintentos robusta, con ejemplos de código prácticos.

¿Qué son los webhooks?

Un webhook es una devolución de llamada HTTP definida por el usuario. En lugar de que tu aplicación consulte una API en busca de actualizaciones, el proveedor envía una solicitud HTTP POST a una URL que especifiques cada vez que ocurre un evento. Esto hace que las integraciones sean eficientes y casi en tiempo real.

Sin embargo, los webhooks se basan en push, lo que significa que tu endpoint debe ser accesible públicamente, manejar carga inesperada y lidiar con solicitudes duplicadas o maliciosas. Ahí es donde entran la firma y los reintentos.

¿Por qué firmar las cargas de webhook?

Sin verificación, cualquiera que conozca la URL de tu webhook podría enviar eventos falsos. Firmar las cargas con un secreto compartido te permite autenticar al remitente y asegurar que la carga no ha sido manipulada.

El enfoque más común es HMAC (Código de Autenticación de Mensajes basado en Hash) usando SHA-256. El proveedor calcula una firma sobre el cuerpo crudo de la solicitud usando una clave secreta y la incluye en una cabecera (por ejemplo, X-Signature). Tu servidor recalcula la firma y las compara.

Implementación de la verificación HMAC

Aquí tienes un ejemplo simple en Node.js usando Express:

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

// Usar el cuerpo crudo para la verificación de firma
app.use(express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-signature'];
  const secret = process.env.WEBHOOK_SECRET;
  const payload = req.body; // Buffer

  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  // Procesar el evento
  const event = JSON.parse(payload);
  console.log('Received event:', event.type);
  res.status(200).send('OK');
});

app.listen(3000, () => console.log('Webhook server running'));

Puntos clave:

Manejo de reintentos: haciendo los webhooks confiables

Las redes fallan, los servidores se caen y los despliegues causan tiempo de inactividad. Un sistema de webhooks confiable debe reintentar las entregas fallidas. Pero los reintentos ingenuos pueden causar procesamiento duplicado y sobrecargar tu sistema.

Estrategias de reintento

Los patrones de reintento comunes incluyen:

La mayoría de los proveedores implementan algo como: reintentar hasta 5 veces con backoff exponencial durante 24 horas.

Idempotencia: la clave para reintentos seguros

Debido a que los reintentos pueden entregar el mismo evento varias veces, tu endpoint debe ser idempotente. Incluye un ID de evento único en la carga y almacena los IDs procesados para omitir duplicados.

Ejemplo usando un conjunto simple en memoria (usa una base de datos en producción):

const processedEvents = new Set();

app.post('/webhook', (req, res) => {
  // ... verificación de firma ...
  const event = JSON.parse(payload);
  if (processedEvents.has(event.id)) {
    return res.status(200).send('Already processed');
  }
  // Procesar evento
  processedEvents.add(event.id);
  res.status(200).send('OK');
});

Para producción, usa una base de datos con una restricción única en el ID del evento.

Mejores prácticas para consumidores de webhooks

Comparación de políticas de reintento

Política Ventajas Desventajas
Intervalo fijo Simple de implementar Puede sobrecargar un sistema en recuperación
Backoff exponencial Reduce la carga durante caídas Retrasa la entrega si el fallo es transitorio
Backoff exponencial con jitter Previene reintentos sincronizados Ligeramente más complejo

Preguntas frecuentes

¿Cómo verifico una firma de webhook?

Calcula el HMAC del cuerpo crudo de la solicitud usando el secreto compartido y compáralo con la cabecera de firma usando una función segura en tiempo. Nunca compares con igualdad simple.

¿Qué debo hacer si mi endpoint de webhook está caído?

El proveedor debe reintentar con backoff exponencial. Asegúrate de que tu endpoint devuelva un 2xx rápidamente y procese los eventos de forma asíncrona para minimizar el impacto del tiempo de inactividad.

¿Puedo usar webhooks sin firma?

No se recomienda. Sin firmas, no puedes verificar al remitente, lo que hace que tu endpoint sea vulnerable a eventos falsos. Siempre usa firmas cuando estén disponibles.

Al probar cargas de webhook, es posible que necesites inspeccionar datos JSON. Usa el Formateador JSON para imprimir y validar cargas rápidamente.