Saltar a contenido

Eventos y webhooks

ZEngine publica eventos de dominio en EventBridge bus zen-dev-domain-events. Integradores pueden suscribirse vía:

  1. Webhook HTTPS (recomendado): registras una URL, ZEngine hace POST con firma HMAC.
  2. Cross-account EventBridge: tu cuenta AWS recibe los eventos directamente (configuración por ticket de plataforma).

Registro

Admin SPA → Integraciones → Webhooks → + Nuevo. Campos:

  • URL HTTPS pública.
  • Filtro de event types (lista o *).
  • Secret para HMAC (se genera o lo provees).

Firma HMAC

Cada POST incluye:

x-zen-signature: t=1747576981,v1=ab12cd...
x-zen-event-type: Conversation.Started
x-zen-event-id: 01HZ...
x-zen-tenant-id: iplacex-demo

v1 es HMAC-SHA256(secret, "{t}.{body}"). Valida tolerancia de timestamp de ±5 min.

const expected = crypto
  .createHmac('sha256', secret)
  .update(`${t}.${rawBody}`)
  .digest('hex');
if (!timingSafeEqual(expected, v1)) reject(401);

Catálogo de eventos

El registro canónico vive en packages/event-contracts/ (Zod + JSON Schema). Resumen V1.1:

Tenant.*

Type Cuándo Payload clave
Tenant.Created Nuevo tenant aprovisionado. tenantId, name, tier, createdAt
Tenant.Updated Cambia configuración (outbox de tenant-mgmt). tenantId, changedFields, version
Tenant.Suspended Tenant suspendido. tenantId, reason

Conversation.*

Type Cuándo Payload clave
Conversation.Started Primera interacción de una sesión. conversationId, channel, widgetId, user
Conversation.MessageReceived Mensaje IN del usuario. conversationId, messageId, text, attachments
Conversation.MessageDelivered Mensaje OUT entregado. conversationId, messageId, channel, provider
Conversation.HandedOff Transferido a humano. conversationId, channel, queue
Conversation.Closed Conversación finalizada. conversationId, duration, resolution

Channel.*

Type Cuándo
Channel.Enabled Canal activado para un tenant.
Channel.Disabled Canal desactivado.
Channel.TemplateApproved Template WhatsApp aprobado por Meta.
Channel.TemplateRejected Template rechazado.

Survey.*

Type Cuándo
Survey.Triggered NPS lanzado tras handoff/close.
Survey.Completed Usuario respondió. Payload incluye score, comment.
Survey.Skipped Usuario cerró sin responder.

Envelope estándar

{
  "id": "01HZ8...",
  "source": "zen.flow-engine",
  "detailType": "Conversation.MessageReceived",
  "time": "2026-05-18T14:23:01.234Z",
  "tenantId": "iplacex-demo",
  "correlationId": "01HZ...",
  "version": 1,
  "detail": { /* payload específico */ }
}

version permite evolución compatible. Bumps mayores → nuevo detailType (p. ej. Conversation.MessageReceived.v2).

Garantías

  • At-least-once delivery. Tu consumer debe ser idempotente por id.
  • Orden: no garantizado entre eventos. Usa time y correlationId.
  • Reintentos: 24h con backoff exponencial. Si tu endpoint devuelve 4xx/5xx persistente, el evento va a DLQ y se notifica al tenant.

Sandbox local

Para probar sin exponer tu localhost: usa ngrok o cloudflared y registra la URL temporal en el Admin SPA. Eventos se redirigirán ahí.