Webhooks

Webhooks let an external system react to things that happen in your space. Each webhook subscribes to one or more events (per action, grouped by module) and receives an HTTP POST whenever a matching event fires.

Manage them in Settings → Developers → Webhooks.

Events

Events are grouped by module, the same way permissions are grouped on the roles page. Tick the exact actions you care about.

ModuleEvent keyFires when
Renderingrender.completedA page finishes rendering (POST /api/render or GET /api/render/:pageId).
Brandsbrand.createdA brand is created.
Brandsbrand.updatedA brand's tokens or details are updated.
Brandsbrand.deletedA brand is deleted.
Contententry.createdA content entry is created in a collection.
Contententry.updatedA content entry is updated.
Contententry.publishedA content entry is published.
Contententry.deletedA content entry is deleted.
ContententryType.createdA content type (collection) is created.
ContententryType.updatedA content type's fields or settings are updated.
ContententryType.deletedA content type is deleted.

Delivery payload

Every delivery is a POST with a JSON body:

{
  "id": "b7c1e0f2-…",          // unique per delivery
  "event": "brand.updated",     // the event key
  "timestamp": "2026-07-08T10:00:00.000Z",
  "spaceId": "665f…",
  "data": { "doc": { "_id": "…", "name": "…" } }
}

The data shape depends on the event — the affected document for create/update, an { id } for delete, and render metadata (pageId, format, width, height, renderMs, file, …) for render.completed.

Headers we set

HeaderDescription
Content-TypeAlways application/json.
X-Webhook-IdThe webhook's id.
X-Webhook-EventThe event key (e.g. brand.updated).
X-Webhook-DeliveryThe unique delivery id (matches id in the body).
X-Webhook-TimestampISO timestamp the event was emitted.
X-Webhook-Signaturesha256=<hex> HMAC of the raw body — only when a secret is set.

Verifying the signature

Set a Secret on the webhook and every delivery is signed. Recompute the HMAC over the raw request body with your secret and compare it (constant-time) to the X-Webhook-Signature header.

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

function verify(rawBody: string, header: string, secret: string): boolean {
  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')
  const a = Buffer.from(header)
  const b = Buffer.from(expected)
  return a.length === b.length && timingSafeEqual(a, b)
}

Reject any request whose signature does not match.

Custom headers

Add any number of custom headers to a webhook — for example a bearer token or a shared secret your receiver checks, or a routing hint. They are sent on every delivery. Reserved headers (Content-Type, User-Agent, and the X-Webhook-* headers above) cannot be overridden.

Delivery behaviour

  • Deliveries are best-effort and fire-and-forget: a failing or slow receiver never fails the render/save that triggered it.
  • Each request times out after 10 seconds.
  • Only public URLs are allowed. The Post URL must be a public https address (SSRF protection): private, loopback, link-local, and cloud-metadata targets are rejected at save time and re-checked at delivery time, and redirects are not followed.

Delivery history & resend

Every attempt is logged. Open a webhook's history (the clock icon in Settings → Developers) to see its recent deliveries with:

  • Statussuccess, failed, or blocked (rejected by the URL guard).
  • Response code returned by your endpoint, and the duration of the request.
  • When it fired, and the error message on failures (hover the timestamp).

Use Resend to replay a past delivery — it sends the same event and data again with a fresh delivery id and signature, so you can retry after fixing your endpoint. Delivery records are retained for 3 months, then removed automatically. Deleting a webhook also removes its history.

  • Only enabled webhooks whose triggers include the event are delivered to.
  • Deliveries run out of the request's critical path, so the API response is not delayed.

Your endpoint should respond quickly with a 2xx and do any heavy work asynchronously.

Summary

AspectDescription
DirectionOutbound — you supply the URL.
TriggerAny subscribed event in your space.
AuthHMAC-SHA256 signature (optional secret) + optional custom headers.
RetriesNone yet; treat delivery as at-most-once.
Impact on APINone; delivery is deferred and best-effort.

Scale your creative process