> ## Documentation Index
> Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook payloads & data

> Reference for ButterCMS webhook JSON payloads — covers the structure of content change data and event metadata for each payload type.

## Payload structure

All webhook payloads follow a consistent structure with two main sections:

```json theme={null}
{
  "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:

| Field    | Type         | Description                                                         |
| -------- | ------------ | ------------------------------------------------------------------- |
| `event`  | string       | The event type that triggered this webhook (e.g., `page.published`) |
| `target` | string (URI) | The webhook endpoint URL that received this notification            |

## Page webhook payloads

### Data fields

| Field          | Type                   | Description                                                                                                            | Required |
| -------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------- |
| `id`           | string                 | Page slug                                                                                                              | Yes      |
| `buttercms_id` | integer                | Page numeric ID                                                                                                        | Yes      |
| `page_type`    | string                 | Page type key, or `*` for single pages                                                                                 | Yes      |
| `editor`       | string                 | Full name of the editor who made the change                                                                            | Yes      |
| `name`         | string                 | Human-readable page name                                                                                               | Yes      |
| `timestamp`    | string                 | Timestamp when webhook was generated                                                                                   | Yes      |
| `locale`       | string                 | Code of the locale a change applies to. Present for locale-scoped changes in localized organizations; absent otherwise | No       |
| `status`       | string                 | Current page status: `draft`, `published`, `scheduled`, or `deleted`                                                   | Yes      |
| `updated`      | string (datetime)      | Last updated timestamp in ISO 8601 format                                                                              | Yes      |
| `published`    | string/null (datetime) | Published timestamp, null if not published                                                                             | No       |
| `scheduled`    | string/null (datetime) | Scheduled publication timestamp, null if not scheduled                                                                 | No       |

### Example: Page published

```json theme={null}
{
  "data": {
    "id": "product-launch",
    "buttercms_id": 5678,
    "page_type": "landing",
    "editor": "Marketing Team",
    "name": "Product Launch Landing Page",
    "timestamp": "2024-01-15T14:30:00",
    "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

```json theme={null}
{
  "data": {
    "id": "old-promotion",
    "buttercms_id": 3456,
    "page_type": "promo",
    "editor": "Content Manager",
    "name": "Old Promotion Page",
    "timestamp": "2024-01-15T20:15:00",
    "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

| Field    | Type    | Description                                                        | Required |
| -------- | ------- | ------------------------------------------------------------------ | -------- |
| `id`     | string  | Blog post slug                                                     | Yes      |
| `_id`    | integer | Blog post numeric ID                                               | Yes      |
| `locale` | string  | Locale code — present only in `post.localization.*` event payloads | No       |

<Info>
  The `post.localization.*` events (`post.localization.published`, `post.localization.draft`, `post.localization.delete`) add a `locale` field identifying which locale changed, e.g. `"locale": "es"`. The default-locale `post.*` events omit this field.
</Info>

### Example: Blog Post published

```json theme={null}
{
  "data": {
    "id": "announcing-new-features",
    "_id": 5678
  },
  "webhook": {
    "event": "post.published",
    "target": "https://yourapp.com/webhooks/buttercms"
  }
}
```

<Info>
  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.
</Info>

### Fetching full post data

```javascript theme={null}
// 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

| Field       | Type   | Description                                                                                                            | Required |
| ----------- | ------ | ---------------------------------------------------------------------------------------------------------------------- | -------- |
| `id`        | string | Collection key identifier                                                                                              | Yes      |
| `itemid`    | string | API URI for retrieving the specific collection item                                                                    | Yes      |
| `label`     | string | Display label for the collection item                                                                                  | Yes      |
| `editor`    | string | Full name of the editor who made the change                                                                            | Yes      |
| `timestamp` | string | Timestamp when webhook was generated                                                                                   | Yes      |
| `locale`    | string | Code of the locale a change applies to. Present for locale-scoped changes in localized organizations; absent otherwise | No       |
| `status`    | string | Current status: `draft`, `published`, or `deleted`                                                                     | Yes      |

### Example: collection item published

```json theme={null}
{
  "data": {
    "id": "products",
    "itemid": "/v2/content/?keys=products[_id=5678]",
    "label": "Wireless Headphones Pro",
    "editor": "Product Manager",
    "timestamp": "2024-01-15T13:45:00",
    "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:

```javascript theme={null}
// 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
});
```

## Media webhook payloads

### media.videouploaded data fields

| Field | Type         | Description                  | Required |
| ----- | ------------ | ---------------------------- | -------- |
| `id`  | string (URI) | The uploaded video's CDN URL | Yes      |

### Example: Media video uploaded

```json theme={null}
{
  "data": {
    "id": "https://cdn.buttercms.com/video/company-promo.mp4"
  },
  "webhook": {
    "event": "media.videouploaded",
    "target": "https://yourapp.com/webhooks/buttercms"
  }
}
```

## Localized content payloads

For **Pages** and **Collection items**, the `locale` field carries the code of the locale a change applies to.

<Info>
  Blog posts behave differently. The default-locale `post.*` events never carry a `locale` field; localized changes fire dedicated `post.localization.*` events that always include it. See [Blog Post webhook payloads](#blog-post-webhook-payloads).
</Info>

### When `locale` is present

For organizations with localization enabled, the `locale` field indicates which locale triggered the event. Content edited in the default locale fires with that locale's code:

```json theme={null}
{
  "data": {
    "id": "homepage",
    "locale": "es",
    ...
  }
}
```

### When `locale` is absent

The field is omitted from the payload entirely for:

* organizations that do not have localization enabled
* delete events (`page.delete`, `collectionitem.delete`), which are not scoped to a locale

```json theme={null}
{
  "data": {
    "id": "homepage",
    ...
  }
}
```

### Handling localized webhooks

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

  // Check whether the event is scoped to a locale
  if (data.locale) {
    // Locale-scoped change (includes the default locale in localized orgs)
    invalidateCache(data.id, data.locale);
  } else {
    // No locale scope: non-localized org, or a delete event
    invalidateCache(data.id, 'default');
  }

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

## Parsing webhook payloads

### TypeScript interface

Define types for webhook payloads to ensure type safety:

```typescript theme={null}
interface WebhookMeta {
  event: string;
  target: string;
}

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

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

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

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

### Event type detection

```javascript theme={null}
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;
  }
}
```
