ObjectOS
Configurar

Webhooks

Entrega, firma y reintentos de webhooks salientes.

Webhooks

ObjectOS utiliza un modelo de outbox persistente para los webhooks salientes. Cuando el plugin de webhooks está habilitado, los cambios de negocio encolan una fila de entrega y un despachador en segundo plano la entrega con reintentos, de modo que un receptor lento o no disponible nunca bloquea la transacción de origen.

Habilitar webhooks

Los webhooks son una capacidad opcional. La imagen de ObjectOS desplegada debe incluir @objectstack/plugin-webhooks, y el artefacto de la aplicación debe registrar las suscripciones de webhook (normalmente como registros de un objeto sys_webhook).

Cuando están habilitados, aparecen dos objetos en la Console:

ObjetoPropósito
sys_webhookSuscripción de webhook (URL de destino, filtro de eventos, secreto, estado)
sys_webhook_deliveryRegistro de entrega (URL, código de respuesta, número de intentos, marca de tiempo de reintento)

Semántica de entrega

  • Al menos una vez. Una entrega puede reintentarse tras un fallo transitorio; los receptores deben ser idempotentes.
  • Persistente. Las entregas sobreviven a los reinicios de ObjectOS porque se almacenan en la base de datos de negocio.
  • Particionada. Cada worker del despachador reclama una partición del outbox para que los despliegues puedan escalar horizontalmente el despacho sin entregas duplicadas.
  • Reintentos acotados. Las entregas fallidas se reintentan con backoff hasta un límite configurable; las filas agotadas permanecen en sys_webhook_delivery para su inspección.

Firma

Cada entrega lleva cabeceras de identificación para que los receptores puedan enrutarla, deduplicarla y verificarla:

X-Objectstack-Event:     <event type, e.g. data.record.created>
X-Objectstack-Delivery:  <delivery id — use as your idempotency key>
X-Objectstack-Attempt:   <attempt number, starting at 1>

Cuando una suscripción de webhook tiene un secret, ObjectOS también firma cada solicitud:

X-Objectstack-Signature: sha256=<hex hmac>

La firma es HMAC-SHA256(secret, body) calculada sobre el cuerpo crudo de la solicitud. Verifícala en el receptor antes de confiar en el payload:

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

function verify(body, signatureHeader, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret).update(body).digest('hex');
  return timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
}

Rota los secretos emitiendo una nueva suscripción con el nuevo secreto, ejecutando ambas durante una ventana de transición y deshabilitando luego la antigua.

Expectativas del receptor

  • Responde con 2xx en unos pocos segundos. Una respuesta 408, 429 o 5xx (o un timeout/error de transporte) es reintentable y se reintenta con backoff. Cualquier otro 4xx se trata como un fallo permanente y se mueve a dead sin más reintentos.
  • El despachador no marca una entrega como exitosa hasta que ve un 2xx, por lo que un receptor fallido mantiene la fila en sys_webhook_delivery para su inspección o reentrega.
  • Sé idempotente: deduplica usando la cabecera X-Objectstack-Delivery (el identificador de entrega) o tu propio identificador de evento en el payload.

Manejo de fallos

Cuando algo falla:

  1. Revisa la fila en sys_webhook_delivery: se registran status, response_code, response_body y attempts.
  2. Confirma el acceso de red saliente desde ObjectOS al receptor.
  3. Si el receptor cambió de forma permanente, actualiza la URL de la suscripción y reentrega la fila desde la Console.
  4. Para la revisión de incidentes, los registros de auditoría (sys_audit_log) capturan las ediciones de las suscripciones, pero no los payloads; los payloads permanecen en el outbox.

Consejos operativos

  • No pongas secretos en las URLs de los webhooks (las cadenas de consulta quedan registradas).
  • Usa un nombre de host de receptor dedicado para poder descargar tráfico bloqueándolo en el borde sin afectar a la aplicación principal.
  • Vigila el retraso del despachador: un outbox que crece normalmente significa que el receptor está degradado.

On this page