> ## 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.

# Webhooks: key concepts

> Configure and manage ButterCMS webhooks for real-time content change notifications.

## Overview

ButterCMS webhooks enable real-time notifications when content changes occur in your account. When you publish a page, update a collection item, or create a blog post, ButterCMS sends an HTTP POST request to your configured endpoint with details about the change.

### Key use cases

* **Cache Invalidation**: Clear your CDN or application cache when content updates
* **Static Site Rebuilds**: Trigger a rebuild of your static site (Next.js, Astro, etc.)
* **Multi-channel Publishing**: Sync content to social media, email lists, or mobile apps
* **Automated Workflows**: Send Slack notifications, update analytics, or trigger deployments

## How webhooks work

```mermaid theme={null}
flowchart LR
    subgraph ButterCMS
        A[ButterCMS Dashboard]
    end

    subgraph Your Server
        B[Your Endpoint<br>/webhooks]
        C[Your Action<br>- Clear cache<br>- Rebuild site<br>- Notify team]
    end

    A -->|HTTP POST<br>JSON payload| B
    B --> C

    subgraph Events[Webhook Events]
        E1[page.published, page.draft, page.delete]
        E2[post.published, post.draft, post.delete]
        E3[collectionitem.published, collectionitem.draft]
    end

    A -.-> Events
```

## Configuring webhooks

Webhooks are configured through the ButterCMS dashboard.

### Step 1: access webhook settings

1. Log in to your [ButterCMS Dashboard](https://buttercms.com/login/)
2. Navigate to **Settings** > **Webhooks**
3. Click **Add Webhook**

### Step 2: configure endpoint

| Field       | Description                                      |
| ----------- | ------------------------------------------------ |
| **URL**     | Your webhook endpoint URL (must be HTTPS)        |
| **Events**  | Select which content events trigger this webhook |
| **Headers** | Optional custom headers for authentication       |

<Note>
  Webhooks require account-level enablement, and availability varies by plan. [Contact support](../../support/contact-status/contact-support) to enable webhooks for your account.
</Note>

### Step 3: select events

Choose which events should trigger webhooks:

**Page Events:**

* `page.published` - Page is published or republished
* `page.draft` - Page is saved as draft
* `page.unpublished` - Page is unpublished
* `page.delete` - Page is deleted
* `page.*` - All page events

**Blog Post Events:**

* `post.published` - Post is published
* `post.draft` - Post is saved as draft
* `post.delete` - Post is deleted or unpublished
* `post.*` - All post events

**Collection Item Events:**

* `collectionitem.published` - Item is published
* `collectionitem.draft` - Item is saved as draft
* `collectionitem.unpublished` - Item is unpublished
* `collectionitem.delete` - Item is deleted
* `collectionitem.*` - All collection events

## Delivery guarantees

<Info>
  Webhooks are delivered asynchronously via a job queue. While webhook delivery is reliable under normal conditions, there is no automatic retry mechanism for failed deliveries. Implement idempotent handling in case the same event is delivered multiple times.
</Info>

### Response handling

| Scenario         | ButterCMS Behavior             |
| ---------------- | ------------------------------ |
| **2xx Response** | Webhook delivered successfully |
| **4xx Response** | Webhook failed (client error)  |
| **5xx Response** | Webhook failed (server error)  |
| **Timeout (5s)** | Webhook failed (timeout)       |

<Warning>
  Webhooks are delivered on a best-effort basis without automatic retries. Implement appropriate logging and error handling on your endpoint to detect missed webhooks.
</Warning>

### Timeout requirement

Your webhook endpoint must respond within **5 seconds**. If your processing takes longer, return a `200` immediately and process asynchronously.

## Security best practices

### Custom authentication headers

Add authentication headers to verify webhook requests originate from ButterCMS:

```
X-Webhook-Secret: your-secret-key
Authorization: Bearer your-token
```

### Endpoint implementation

```javascript theme={null}
const express = require('express');
const app = express();

// Verify webhook authenticity
function verifyWebhook(req) {
  const secret = req.headers['x-webhook-secret'];
  return secret === process.env.WEBHOOK_SECRET;
}

app.post('/webhooks/buttercms', express.json(), (req, res) => {
  // Verify authentication
  if (!verifyWebhook(req)) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  // Process webhook (respond quickly, process async if needed)
  const { data, webhook } = req.body;
  console.log(`Received ${webhook.event} for ${data.id}`);

  // Queue for async processing if needed
  processWebhookAsync(req.body);

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

### Additional security measures

* **HTTPS Only**: Always use HTTPS endpoints for encrypted transmission
* **IP Allowlisting**: Restrict access to ButterCMS IP ranges if possible
* **Validate Payloads**: Check that payload structure matches expected schema
* **Idempotency**: Handle duplicate deliveries using event timestamps or content IDs

## Handling duplicates

Since webhooks may be delivered multiple times, implement idempotent processing:

```javascript theme={null}
const processedEvents = new Set();

async function handleWebhook(payload) {
  const eventKey = `${payload.webhook.event}-${payload.data.id}-${payload.data.updated}`;

  if (processedEvents.has(eventKey)) {
    console.log('Duplicate event, skipping');
    return;
  }

  processedEvents.add(eventKey);

  // Process the webhook
  await processEvent(payload);

  // Clean up old events periodically
  // (in production, use Redis or database with TTL)
}
```

## Testing webhooks

### Local development

Use tools like [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) to expose your local server:

```bash theme={null}
# Expose local port 3000
ngrok http 3000

# Use the generated URL in ButterCMS webhook settings
# https://abc123.ngrok.io/webhooks/buttercms
```

### Webhook debugging

Log incoming webhooks for debugging:

```javascript theme={null}
app.post('/webhooks/buttercms', express.json(), (req, res) => {
  // Log full payload for debugging
  console.log('Webhook received:', JSON.stringify(req.body, null, 2));
  console.log('Headers:', req.headers);

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

## Next steps

<CardGroup cols={2}>
  <Card title="Webhook Events" icon="list" href="../../api-reference/page-events/webhook-page-published">
    Event types and payloads
  </Card>

  <Card title="Cache Invalidation" icon="rotate" href="/build-your-app/webhooks-events/cache-invalidation-webhooks">
    Use webhooks for caching
  </Card>

  <Card title="Real-Time Sync" icon="arrows-rotate" href="/build-your-app/webhooks-events/real-time-synchronization">
    Real-time content sync
  </Card>

  <Card title="Monitoring" icon="chart-line" href="/build-your-app/webhooks-events/webhook-monitoring-debugging">
    Monitoring and debugging
  </Card>
</CardGroup>
