Skip to main content

Payload structure

All webhook payloads follow a consistent structure with two main sections:
{
  "data": {
    // Content-specific data about the changed item
  },
  "webhook": {
    "event": "event.type",
    "target": "https://your-webhook-endpoint.com"
  }
}

Webhook metadata

The webhook object is included in all webhook payloads and contains:
FieldTypeDescription
eventstringThe event type that triggered this webhook (e.g., page.published)
targetstring (URI)The webhook endpoint URL that received this notification

Page webhook payloads

Data fields

FieldTypeDescriptionRequired
idstringPage slugYes
buttercms_idintegerPage numeric IDYes
page_typestringPage type key, or * for single pagesYes
editorstringFull name of the editor who made the changeYes
namestringHuman-readable page nameYes
timestampstringTimestamp when webhook was generatedYes
localestring/nullLocale code for localized content, null for default localeNo
statusstringCurrent page status: draft, published, scheduled, or deletedYes
updatedstring (datetime)Last updated timestamp in ISO 8601 formatYes
publishedstring/null (datetime)Published timestamp, null if not publishedNo
scheduledstring/null (datetime)Scheduled publication timestamp, null if not scheduledNo

Example: Page published

{
  "data": {
    "id": "product-launch",
    "buttercms_id": 5678,
    "page_type": "landing",
    "editor": "Marketing Team",
    "name": "Product Launch Landing Page",
    "timestamp": "2024-01-15T14:30:00",
    "locale": null,
    "status": "published",
    "updated": "2024-01-15T14:30:00.123456Z",
    "published": "2024-01-15T14:30:00.123456Z",
    "scheduled": null
  },
  "webhook": {
    "event": "page.published",
    "target": "https://yourapp.com/webhooks/buttercms"
  }
}

Example: Page deleted

{
  "data": {
    "id": "old-promotion",
    "buttercms_id": 3456,
    "page_type": "promo",
    "editor": "Content Manager",
    "name": "Old Promotion Page",
    "timestamp": "2024-01-15T20:15:00",
    "locale": null,
    "status": "deleted",
    "updated": "2024-01-15T20:15:00.111222Z",
    "published": "2024-01-10T10:00:00.000000Z",
    "scheduled": null
  },
  "webhook": {
    "event": "page.delete",
    "target": "https://yourapp.com/webhooks/buttercms"
  }
}

Blog Post webhook payloads

Data fields

FieldTypeDescriptionRequired
idstringBlog post slugYes
_idintegerBlog post numeric IDYes

Example: Blog Post published

{
  "data": {
    "id": "announcing-new-features",
    "_id": 5678
  },
  "webhook": {
    "event": "post.published",
    "target": "https://yourapp.com/webhooks/buttercms"
  }
}
Blog post webhook payloads are intentionally lightweight, containing only the post slug and ID. To get the full post content, use the slug to fetch the complete post data from the ButterCMS API.

Fetching full post data

// After receiving the webhook
const { data, webhook } = webhookPayload;

if (webhook.event === 'post.published') {
  // Fetch the full post using the slug
  const butter = require('buttercms')('your-api-token');
  const response = await butter.post.retrieve(data.id);
  const fullPost = response.data.data;

  // Now you have access to all post fields:
  // fullPost.title, fullPost.body, fullPost.author, etc.
}

Collection item webhook payloads

Data fields

FieldTypeDescriptionRequired
idstringCollection key identifierYes
itemidstringAPI URI for retrieving the specific collection itemYes
labelstringDisplay label for the collection itemYes
editorstringFull name of the editor who made the changeYes
timestampstringTimestamp when webhook was generatedYes
localestring/nullLocale code for localized content, null for default localeNo
statusstringCurrent status: draft, published, or deletedYes

Example: collection item published

{
  "data": {
    "id": "products",
    "itemid": "/v2/content/?keys=products[_id=5678]",
    "label": "Wireless Headphones Pro",
    "editor": "Product Manager",
    "timestamp": "2024-01-15T13:45:00",
    "locale": null,
    "status": "published"
  },
  "webhook": {
    "event": "collectionitem.published",
    "target": "https://yourapp.com/webhooks/buttercms"
  }
}

Fetching full collection item data

The itemid field contains the API path to fetch the specific item:
// After receiving the webhook
const { data } = webhookPayload;

// The itemid contains the API query path
// e.g., "/v2/content/?keys=products[_id=5678]"

// Fetch the full item using the ButterCMS client
const butter = require('buttercms')('your-api-token');

// Extract the collection key and item ID
const collectionKey = data.id;  // "products"
const itemFilter = `[_id=${extractId(data.itemid)}]`;

const response = await butter.content.retrieve([collectionKey], {
  [collectionKey]: itemFilter
});

Localized content payloads

For organizations with localization enabled, the locale field indicates which locale triggered the event:

Default locale

When content in the default locale is changed, locale is null:
{
  "data": {
    "id": "homepage",
    "locale": null,
    ...
  }
}

Specific locale

When content in a specific locale is changed, locale contains the locale code:
{
  "data": {
    "id": "homepage",
    "locale": "es",
    ...
  }
}

Handling localized webhooks

app.post('/webhooks/buttercms', (req, res) => {
  const { data, webhook } = req.body;

  // Check if this is for a specific locale
  if (data.locale) {
    // Handle locale-specific cache invalidation
    invalidateCache(data.id, data.locale);
  } else {
    // Handle default locale
    invalidateCache(data.id, 'default');
  }

  res.status(200).json({ received: true });
});

Parsing webhook payloads

TypeScript interface

Define types for webhook payloads to ensure type safety:
interface WebhookMeta {
  event: string;
  target: string;
}

interface PageWebhookData {
  id: string;
  buttercms_id: number;
  page_type: string;
  editor: string;
  name: string;
  timestamp: string;
  locale: string | null;
  status: 'draft' | 'published' | 'scheduled' | 'deleted';
  updated: string;
  published: string | null;
  scheduled: string | null;
}

interface BlogPostWebhookData {
  id: string;
  _id: number;
}

interface CollectionItemWebhookData {
  id: string;
  itemid: string;
  label: string;
  editor: string;
  timestamp: string;
  locale: string | null;
  status: 'draft' | 'published' | 'deleted';
}

interface WebhookPayload<T> {
  data: T;
  webhook: WebhookMeta;
}

Event type detection

function handleWebhook(payload) {
  const { event } = payload.webhook;

  // Parse event type
  const [contentType, action] = event.split('.');

  switch (contentType) {
    case 'page':
      handlePageEvent(action, payload.data);
      break;
    case 'post':
      handlePostEvent(action, payload.data);
      break;
    case 'collectionitem':
      handleCollectionEvent(action, payload.data);
      break;
    case 'media':
      handleMediaEvent(action, payload.data);
      break;
  }
}