Webhooks

Los webhooks notifican cambios de un correo a tu backend. Su administración requiere sesión humana de propietario o administrador; no está disponible para claves de integración. La pantalla Desarrolladores todavía no incluye un formulario para configurarlos.

Configura el destino

La superficie de sesión usa POST /workspaces/{workspaceId}/webhooks, GET de lista/detalle y PATCH /workspaces/{workspaceId}/webhooks/{id}. Las escrituras requieren idempotencia; PATCH requiere además el ETag en If-Match. En el navegador, la fachada /api/workspaces/... aplica sesión, origen y CSRF.

Ejemplo de cuerpo de creación:

{
  "url": "https://hooks.example.com/sendiro",
  "events": ["email.delivered", "email.bounced", "email.complained"],
  "enabled": true
}

Sustituye el destino por un servicio tuyo. Debe usar HTTPS en puerto 443 y resolver a IPv4 público; no se admiten IP literales, destinos privados ni redirecciones. Hay un máximo de 20 endpoints. El secreto se revela una vez al crear, sin volver a aparecer al repetir la operación idempotente.

Catálogo y envelope

Eventos configurables: email.queued, email.submitted, email.submission_unknown, email.delivered, email.bounced, email.complained, email.opened, email.clicked, email.unsubscribed, email.failed y email.suppressed.

El JSON contiene schemaVersion: 1, id, createdAt y event, con id, workspaceId, emailId, kind, occurredAt y recordedAt. No incluye el cuerpo del correo. occurredAt describe el evento; recordedAt, su registro.

Verifica antes de procesar

Lee X-Sendiro-Event-Id, X-Sendiro-Delivery-Id y X-Sendiro-Signature. Esta última tiene formato t=TIMESTAMP,v1=HEX.

Calcula HMAC-SHA256 con el secreto sobre timestamp + "." + rawBody, usando los bytes originales, y compara en tiempo constante. Aplica una ventana de antigüedad del timestamp en tu receptor y rechaza firmas inválidas antes de usar los datos. Parsear y volver a serializar el JSON cambia los bytes firmados.

Rota un secreto de firma

Un administrador puede llamar a POST /workspaces/{workspaceId}/webhooks/{id}/rotate-secret con sesión humana, Idempotency-Key y el ETag actual de configuración en If-Match. Para una renovación programada, envía:

{"mode":"overlap","overlapSeconds":3600,"reason":"Renovación programada del receptor"}

La respuesta revela el nuevo secret una vez e incrementa la revisión del webhook. Los listados, detalles y reintentos idempotentes no revelan claves. Guarda de forma segura la primera respuesta; perderla requiere otra rotación explícita. El solapamiento predeterminado dura una hora, con mínimo de cinco minutos y máximo de 24 horas. Durante esa ventana, la cabecera es t=TIMESTAMP,v1=HEX_NUEVA,v1=HEX_ANTERIOR: verifica cada candidato v1 y acepta si cualquiera coincide con tu clave configurada mediante comparación constante. Instala la clave nueva antes de secretRotation.overlapExpiresAt y retira la anterior del receptor. Otra rotación gradual se bloquea mientras haya una activa.

Si la clave está comprometida, envía explícitamente {"mode":"immediate","reason":"El receptor informó una clave comprometida"}. Esto revoca inmediatamente todas las claves de firma anteriores, incluso un solapamiento activo, y puede interrumpir entregas hasta que el receptor instale la nueva. Quien conserve una clave anterior puede falsificar solicitudes hacia un receptor que todavía la acepte; retira también del receptor las claves comprometidas. Las entregas pendientes usan claves vigentes al invocar y conservan IDs de evento y entrega. Una petición ya enviada no se puede retirar. Los despliegues de Sendiro no rotan secretos automáticamente.

Confirma y deduplica

Persiste el ID de evento junto con el efecto de negocio en una transacción o aplica idempotencia equivalente. El mismo evento puede llegar más de una vez y fuera de orden; conserva su identidad aunque repita el POST. Devuelve 2xx cuando lo hayas aceptado de forma durable.

Otras respuestas y errores reintentan con espera creciente y presupuesto finito; después el trabajo queda bloqueado para revisión. No hay garantía de llegada eventual ante un fallo permanente. Consulta entregas mediante GET /workspaces/{workspaceId}/webhook-deliveries con sesión administrativa. Deshabilitar cancela pendientes cuando se procesan y no revierte eventos ya recibidos.