Ir al contenido
Volver a la documentación para desarrolladores

Guía de webhooks

Cómo recibir y verificar los eventos que Mailronix envía a tu dirección: entrega, firma, contenido, reintentos y rotación del secreto.

Cómo llegan las entregas

Cada evento es una petición POST con cuerpo JSON a la dirección HTTPS que registraste (puerto 443 u 8443). Responde en menos de 10 segundos: cualquier código 2xx confirma la entrega. Cualquier otra cosa es un error y provoca un nuevo intento, incluidas las redirecciones, que no se siguen. Las direcciones no accesibles desde Internet público se rechazan.

Mailronix-Signature
La firma de la petición. Consulta «Verificar la firma».
Mailronix-Event-Id
El identificador del evento, igual al campo id del cuerpo. Es el mismo en cada intento.
Mailronix-Delivery-Id
El identificador de la entrega. Cítalo cuando escribas a soporte.
Mailronix-Event-Type
El tipo de evento, igual al campo type del cuerpo.

Verificar la firma

Verifica siempre la firma antes de fiarte del contenido: cualquiera que conozca tu dirección puede enviarle una petición. La firma es el HMAC-SHA256, en hexadecimal, de la cadena «t.cuerpo», con el cuerpo exactamente como lo recibiste.

Mailronix-Signature: t=<unix>,v1=<hmac-sha256>
  v1 = hex( HMAC-SHA256( chiave, "<t>." + corpo ) )
  1. Clave: el secreto que la consola muestra una sola vez tiene la forma «whsec_…». La clave HMAC son los bytes que siguen al prefijo, decodificados desde base64url sin relleno. El texto del secreto no es la clave.
  2. Cuerpo: calcula el HMAC sobre los bytes en bruto recibidos. Si tu framework analiza el JSON antes que tú, recupera el cuerpo en bruto (en Express, express.raw): reescribir el JSON cambia los bytes y la firma no coincide.
  3. Frescura: rechaza las peticiones en las que t se aleje más de cinco minutos de la hora actual. t es el instante de cada intento, así que un reintento horas después también supera la comprobación.
  4. Varias firmas: en las 24 horas posteriores a una rotación la cabecera contiene dos valores v1, uno para el secreto nuevo y otro para el anterior. Acepta la petición si cualquiera de ellos coincide con alguno de los secretos que conoces.
  5. Comparación: usa una comparación en tiempo constante, como en los ejemplos.

Ejemplos de verificación

import { createHmac, timingSafeEqual } from 'node:crypto'

// `segreto` è quello mostrato dalla console, «whsec_…». La chiave HMAC sono i
// suoi byte: si toglie il prefisso e si decodifica da base64url.
const chiave = (segreto) => Buffer.from(segreto.replace(/^whsec_/, ''), 'base64url')

// `corpo` è il corpo ESATTO ricevuto (Buffer), non il JSON riscritto.
export function verificaFirma(intestazione, corpo, segreti, toleranza = 300) {
  const parti = intestazione.split(',').map((p) => p.trim().split('='))
  const t = parti.find(([k]) => k === 't')?.[1]
  const firme = parti.filter(([k]) => k === 'v1').map(([, v]) => v)
  if (!t || firme.length === 0) return false
  if (Math.abs(Date.now() / 1000 - Number(t)) > toleranza) return false

  let valida = false
  for (const segreto of segreti) {
    const atteso = createHmac('sha256', chiave(segreto)).update(`${t}.`).update(corpo).digest()
    for (const firma of firme) {
      const ricevuta = Buffer.from(firma, 'hex')
      if (ricevuta.length === atteso.length && timingSafeEqual(ricevuta, atteso)) valida = true
    }
  }
  return valida
}

Ejemplos ejecutados contra la firma real de Mailronix. Si la verificación falla, responde 401; tras aceptar el evento, responde 200 enseguida y trabaja después.

Eventos y contenido

Todos los cuerpos tienen el mismo sobre; el contenido de data cambia según el tipo.

{
  "id": "evt_01j9x4k2m7q8r5t3v6w1y0z2ab",
  "type": "email.bounced",
  "api_version": "2026-10-22",
  "created_at": "2026-10-22T14:03:11Z",
  "brand_id": "6f1c7d0e-5a3b-4e8f-9c21-0b7d4a1e3f52",
  "data": {
    "email_log_id": "b2d4f6a8-1c3e-4a5b-8d7f-9e0a1b2c3d4e",
    "recipient": "[email protected]",
    "category": "transactional",
    "bounce_type": "permanent"
  }
}
  • id: el identificador del evento. Úsalo para reconocer duplicados.
  • type: uno de los tipos de la lista de abajo, o webhook.test para la entrega de prueba.
  • api_version: la versión del formato.
  • created_at: cuándo ocurrió el evento, en UTC.
  • brand_id: la marca a la que pertenece el evento (null solo en webhook.test).
  • Los eventos email.* llevan en data email_log_id, recipient y category. email.bounced añade bounce_type (permanent, transient o undetermined): un rebote anunciado como transient y reclasificado después como permanent produce un segundo email.bounced.
  • Los eventos contact.* llevan en data contact_id y email. contact_id puede ser null en contact.unsubscribed, por ejemplo cuando la baja llega desde una revocación: contempla ese caso.

Tipos de evento

email.sent
webhookGuide.eventTypes.email.sent
email.delivered
webhookGuide.eventTypes.email.delivered
email.bounced
webhookGuide.eventTypes.email.bounced
email.complained
webhookGuide.eventTypes.email.complained
email.failed
webhookGuide.eventTypes.email.failed
email.suppressed
webhookGuide.eventTypes.email.suppressed
contact.confirmed
webhookGuide.eventTypes.contact.confirmed
contact.unsubscribed
webhookGuide.eventTypes.contact.unsubscribed

No hay eventos de apertura: Mailronix no los registra, por decisión de privacidad. Los eventos email.clicked solo llegan de las marcas que activaron el seguimiento de clics y solo para los destinatarios que aceptaron; describen un clic detectado (escáneres y vistas previas pueden generarlos) y llevan el host del destino, no la URL. La revocación bloquea nuevas detecciones y no convierte retroactivamente en ilícito el evento ya recogido: los eventos anteriores ya en cola pueden llegar después, dentro de los 30 días de conservación de la cola. La eliminación del contacto elimina los eventos y las entregas en cola conforme al procedimiento previsto. El cliente receptor del webhook sigue siendo responsable de sus propias copias y de la gestión de los derechos de los interesados respecto a ellas.

Reintentos, duplicados y orden

  • Una entrega fallida se reintenta hasta diez veces en casi cuatro días: de inmediato y luego a los 10 segundos, 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas, 12 horas, 24 horas y 48 horas.
  • Cada evento llega al menos una vez, no exactamente una: puede llegar dos veces, por ejemplo si respondes después del límite de 10 segundos. Guarda los id ya procesados e ignora los duplicados.
  • El orden de llegada no está garantizado: un email.delivered puede llegar después de un email.bounced. Para ordenar los eventos usa created_at, no la hora en que los recibes.
  • Si un evento agota los intentos y en los últimos tres días no ha tenido éxito ninguna entrega a ese endpoint, el endpoint se desactiva y el propietario recibe un correo. Desde la página de Webhooks puedes reactivarlo (se pide la contraseña) y reenviar eventos concretos. Las entregas se conservan 30 días.

Rotar el secreto

Desde la página de Webhooks puedes rotar el secreto de un endpoint (se pide la contraseña); el secreto nuevo se muestra una sola vez. Durante 24 horas cada entrega lleva dos firmas, la del secreto nuevo y la del anterior: acepta ambos secretos en ese tiempo y actualiza tu receptor sin perder entregas. Si el secreto antiguo se ha filtrado, elige revocarlo de inmediato: desde ese momento solo cuenta el nuevo.

Probar el receptor

Al crear un endpoint y con la acción «Enviar prueba», Mailronix envía un evento webhook.test con el mismo sobre y la misma firma que los eventos reales, sin datos de destinatarios. Si la prueba falla, el endpoint se guarda pero queda desactivado.

Límites

Los endpoints activos por cuenta son 1 con el plan Free, 5 con Starter y 10 con Growth. Los endpoints se configuran solo desde la consola, con la sesión y nunca con una clave de API.

Crear una cuenta gratuita