Webhooks
Eventos de entrega en la URL de tu sistema, firmados con HMAC-SHA256.
Registrar
{
"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.
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
| Evento | Cuándo |
|---|---|
delivered | El servidor del destinatario aceptó el mensaje. |
deferred | Fallo temporal; AllyOneMail volverá a intentarlo. No es un bounce. |
bounced | El destino rechazó el mensaje. |
complained | El destinatario lo marcó como spam (feedback loop del proveedor). |
opened | Apertura registrada por el píxel. |
clicked | Clic en un enlace rastreado (url en el payload). |
unsubscribed | Baja por el enlace o por el header de un clic. |
blocked | Envío detenido antes de salir (destinatario suprimido o bloqueado). |
domain_verified | El dominio pasó la verificación de DNS. |
ip_paused | Una IP de envío se pausó por reputación. |
reputation_dropped | Caída fuerte de reputación de una IP (trae tasas de rebote y queja). |
billing_threshold_reached | El consumo del mes cruzó un umbral de alerta del plan. |
incident_escalated | Incidente de entregabilidad escalado (alerta operativa). |
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
2xxen 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 conPOST /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
2xxrápido y procesa en una cola de tu lado.
Probar
Dispara un delivered sintético a tu URL, firmado con el mismo secret.
