Features

Webhooks and the outbox

Durable events written with each change, delivered as signed webhooks.


Every change writes an event to cms_outbox in the same batch as the change: create, update, delete, publish, unpublish, review:request, review:withdraw, global:update, media:create, media:delete, schema:propose, schema:apply, schema:reject.

engine.processOutbox(handler, { limit?, maxAttempts?, retainDelivered? }) hands pending events to your handler. A handler that rejects leaves the event pending for a retry with backoff, up to maxAttempts (default 5).

import type { CMSEvent } from "@interactive-inc/cms"
import { dispatchWebhooks } from "@interactive-inc/cms/webhooks"

export async function deliverOutboxEvent(event: CMSEvent) {
  const failures = await dispatchWebhooks({
    webhooks: [{ url: env.CMS_WEBHOOK_URL, events: [event.event], secret: env.CMS_WEBHOOK_SECRET }],
    event: event.event,
    collection: event.collection ?? "",
    doc: event.doc,
  })

  if (failures.length > 0) return Promise.reject(failures[0])
}

Deliveries POST { event, collection, doc, at } with an x-cms-event header and, when a secret is set, an HMAC-SHA256 hex signature in x-cms-signature. signPayload and deliverWebhook are exported for custom delivery.