HermesHermesDocs
DocsWebhooks
10 min de lectura

Descripción general

Los webhooks permiten que tu aplicación reciba notificaciones en tiempo real cuando ocurren eventos de correo. Hermes envía una solicitud HTTP POST a tu endpoint por cada evento.

Configurar un webhook

  1. En el dashboard de Hermes, ve a Webhooks → Agregar Webhook
  2. Ingresa la URL de tu endpoint (debe ser HTTPS)
  3. Selecciona los eventos que deseas recibir
  4. Haz clic en Guardar

Tipos de eventos

EventoDescripción
deliveredEl correo fue entregado exitosamente al servidor del destinatario
bounce_hardFalla de entrega permanente — la dirección no existe o el dominio la rechazó
bounce_softFalla de entrega temporal — buzón lleno o servidor temporalmente no disponible
complaintEl destinatario marcó el correo como spam
Note

Nota: Los eventos de apertura y clic de correo no están disponibles aún.

Estructura del payload

Todos los eventos comparten el mismo sobre:

{
  "event": "delivered",
  "email_id": "a1b2c3d4-...",
  "timestamp": "2026-05-29T14:32:00.000",
  "metadata": {}
}

El campo metadata contiene detalles específicos del evento.

Payload de bounce_hard y bounce_soft

{
  "event": "bounce_hard",
  "email_id": "a1b2c3d4-...",
  "timestamp": "2026-05-29T14:32:10.000",
  "metadata": {
    "bounce_type": "Permanent",
    "bounce_subtype": "General",
    "bounced_recipients": ["[email protected]"],
    "diagnostic_codes": ["smtp; 550 5.1.1 The email account that you tried to reach does not exist"]
  }
}

Los valores de bounce_type de SES: Permanent, Transient, Undetermined.

Payload de complaint

{
  "event": "complaint",
  "email_id": "a1b2c3d4-...",
  "timestamp": "2026-05-29T14:32:15.000",
  "metadata": {
    "complaint_feedback_type": "abuse",
    "complained_recipients": ["[email protected]"]
  }
}

Verificar firmas de webhook

Cada solicitud de Hermes incluye un encabezado X-Hermes-Signature. Siempre verifica esto antes de procesar.

La firma es sha256= seguido del digest hexadecimal HMAC-SHA256 del cuerpo bruto de la solicitud, usando tu clave de firma de webhook. El cuerpo es JSON compacto (sin espacios adicionales).

Python

import hmac
import hashlib
 
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
 
@app.post("/webhooks/hermes")
async def handle_webhook(request: Request):
    payload = await request.body()
    sig = request.headers.get("X-Hermes-Signature", "")
    if not verify_signature(payload, sig, WEBHOOK_SECRET):
        raise HTTPException(status_code=401)
    event = await request.json()
    # procesar evento...

Node.js

const crypto = require('crypto');
 
function verifySignature(payload, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}
 
app.post('/webhooks/hermes', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verifySignature(req.body, req.headers['x-hermes-signature'] || '', process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Firma inválida' });
  }
  const event = JSON.parse(req.body);
  res.json({ received: true });
});

Comportamiento de reintentos

Si tu endpoint devuelve un estado no-2xx o tarda más de 10 segundos, Hermes reintenta con backoff exponencial:

IntentoEspera
1er reintento1 minuto
2do reintento2 minutos
3er reintento4 minutos

Después de 3 reintentos fallidos, el evento se descarta.

Buenas prácticas

  • Siempre verifica el encabezado X-Hermes-Signature antes de procesar
  • Responde en menos de 10 segundos con un estado 2xx — procesa de forma asíncrona si es necesario
  • Usa email_id para idempotencia — puedes recibir el mismo evento más de una vez
  • Usa únicamente endpoints HTTPS
← Anterior
Configuración de Dominio
Siguiente →
Manejo de Rebotes