AllyOneMail / Webhooks

Webhooks

Eventos de entrega en la URL de tu sistema, firmados con HMAC-SHA256.

Registrar

POST/api/v1/webhooks
{
  "url": "https://tu-app.com/webhooks/allyonemail",
  "events": ["delivered", "bounced", "complained"],
  "description": "Producción"
}

Exige el alcance admin (o el panel). La URL debe ser pública — se rechazan las direcciones internas.

Guarda el secret ahora

El secret completo aparece solo en esta respuesta; las lecturas posteriores lo muestran enmascarado. Para ver un valor nuevo, usa POST /api/v1/webhooks/:id/rotate-secret.

Eventos

EventoCuándo
deliveredEl servidor del destinatario aceptó el mensaje.
deferredFallo temporal; AllyOneMail volverá a intentarlo. No es un bounce.
bouncedEl destino rechazó el mensaje.
complainedEl destinatario lo marcó como spam (feedback loop del proveedor).
openedApertura registrada por el píxel.
clickedClic en un enlace rastreado (url en el payload).
unsubscribedBaja por el enlace o por el header de un clic.
blockedEnvío detenido antes de salir (destinatario suprimido o bloqueado).
domain_verifiedEl dominio pasó la verificación de DNS.
ip_pausedUna IP de envío se pausó por reputación.
reputation_droppedCaída fuerte de reputación de una IP (trae tasas de rebote y queja).
billing_threshold_reachedEl consumo del mes cruzó un umbral de alerta del plan.
incident_escalatedIncidente de entregabilidad escalado (alerta operativa).
Entregas repetidas

El mismo evento puede llegar más de una vez — por un reintento, o porque delivered se emite cuando el servidor de envío acepta el mensaje y otra vez en la confirmación final de entrega. Deduplica por X-AllyOneMAIL-Id, o por message_id + event.

Payload

{
  "event": "bounced",
  "message_id": "msg_a1b2c3",
  "to": "cliente@destino.com",
  "provider": "gmail",
  "response": "550 5.1.1 The email account that you tried to reach does not exist",
  "timestamp": "2026-10-01T13:00:00.000Z",
  "client_id": "c1f0..."
}

Todo payload trae client_id. Los eventos de envío traen message_id, to, provider y, según el origen, from, response (la respuesta del servidor del destinatario) y latency_ms. opened y unsubscribed traen message_id, to y timestamp; clicked trae también url.

Validar la firma

X-AllyOneMAIL-Event: bounced
X-AllyOneMAIL-Sig: sha256=<hex>

Headers X-AllyOneMAIL-Event (el evento) y X-AllyOneMAIL-Sig: sha256= + HMAC-SHA256 del cuerpo bruto con el secret. Calcúlalo sobre los bytes recibidos, antes del parse. El header X-AllyOneMAIL-Id identifica la entrega y se repite en los reintentos.

const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
// compara en tiempo constante con el header X-AllyOneMAIL-Sig

Entrega y fallos

  • Éxito es cualquier 2xx en hasta 10 segundos; no se siguen redirecciones.
  • Ante un fallo, hasta 3 intentos: enseguida, tras ~1 minuto y tras ~2 minutos.
  • Cada intento queda en GET /api/v1/webhooks/:id/deliveries (se guardan 90 días). Reenvía una entrega con POST /api/v1/webhooks/:id/deliveries/:deliveryId/retry.
  • Tras 10 entregas seguidas que fallan los 3 intentos, el webhook se pausa. Corrige el endpoint y reactívalo con PATCH /api/v1/webhooks/:id.
  • Responde 2xx rápido y procesa en una cola de tu lado.

Probar

POST/api/v1/webhooks/:id/test

Dispara un delivered sintético a tu URL, firmado con el mismo secret.

Webhooks — AllyOneMail