Skip to content

Webhooks API

Internal Application API · Enterprise Edition

Webhook management is an internal SPA route (session-authenticated) — there is no public, key-gated management surface. Outbound webhook delivery is an Enterprise-Edition feature. To learn how to consume webhook events, see the Webhooks guide.

Studio supports outbound webhooks that notify external services when content events occur. Webhooks are project-scoped and managed through the enterprise bridge.

All webhook management endpoints are project-scoped:

/api/workspaces/:workspaceId/projects/:projectId/webhooks/...

These are part of Studio's authenticated application API (session-based, used by the Studio SPA) — there is no public, key-gated webhook management surface.

Enterprise Feature

Webhook management requires the enterprise bridge (ee/) and the api.webhooks_outbound feature flag. Outbound webhooks are not available in the self-hosted Community Edition.

List Webhooks

GET /api/workspaces/:workspaceId/projects/:projectId/webhooks

Response

json
[
  {
    "id": "uuid",
    "name": "Production Webhook",
    "url": "https://api.example.com/hooks/contentrain",
    "events": ["content.saved", "content.deleted", "form.submitted"],
    "active": true,
    "created_at": "2026-01-01T00:00:00Z"
  }
]

Create Webhook

POST /api/workspaces/:workspaceId/projects/:projectId/webhooks

Request Body

FieldTypeRequiredDescription
namestringYesDisplay name
urlstringYesDelivery URL (HTTPS)
eventsstring[]YesEvents to subscribe to

Supported Events

EventDescription
content.savedContent entry created or updated
content.deletedContent entry deleted
model.savedModel definition created or updated
branch.mergedContent branch merged
branch.rejectedContent branch rejected (deleted)
cdn.build_completeA CDN build finished
media.uploadedA media asset was uploaded
form.submittedForm submission received

Response

json
{
  "id": "uuid",
  "name": "Production Webhook",
  "url": "https://api.example.com/hooks/contentrain",
  "events": ["content.saved"],
  "secret": "whsec_generated-hmac-secret",
  "active": true
}

WARNING

The secret is only returned once at creation time. Use it to verify webhook payloads via HMAC-SHA256.


Update Webhook

PATCH /api/workspaces/:workspaceId/projects/:projectId/webhooks/:webhookId
FieldTypeRequiredDescription
namestringNoNew display name
urlstringNoNew delivery URL
eventsstring[]NoNew event subscriptions
activebooleanNoEnable/disable

Delete Webhook

DELETE /api/workspaces/:workspaceId/projects/:projectId/webhooks/:webhookId

Test Webhook

Send a test payload to verify connectivity.

POST /api/workspaces/:workspaceId/projects/:projectId/webhooks/:webhookId/test

List Deliveries

Get delivery history for a webhook.

GET /api/workspaces/:workspaceId/projects/:projectId/webhooks/:webhookId/deliveries

Response

json
{
  "deliveries": [
    {
      "id": "uuid",
      "event": "content.saved",
      "status": "delivered",
      "response_status": 200,
      "duration_ms": 150,
      "created_at": "2026-01-15T12:00:00Z"
    }
  ],
  "total": 25
}

Delivery Statuses

StatusDescription
pendingAwaiting delivery
deliveredSuccessfully delivered (2xx response)
failedDelivery failed (non-2xx or timeout)
retryingScheduled for retry

Plan Limits

PlanWebhook Endpoints
Starter3
Pro10
EnterpriseUnlimited

Webhook Payload Format

json
{
  "event": "content.saved",
  "projectId": "uuid",
  "timestamp": "2026-01-15T12:00:00.000Z",
  "data": {
    "models": ["blog-post"],
    "locale": "en",
    "source": "api"
  }
}

The top-level envelope is always { event, projectId, timestamp, data }. The data object is event-specific (see Webhooks guide).

Signature Verification

Webhook payloads include an X-Contentrain-Signature header containing an HMAC-SHA256 signature:

ts
import { createHmac } from 'crypto'

function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expected = createHmac('sha256', secret).update(payload).digest('hex')
  return signature === expected
}

Released under the AGPL-3.0 License.