# Webhook events

Source: https://capacms.com/docs/webhooks/events

Every webhook event, when it fires, and a sample of the data it carries.

Every event an endpoint can subscribe to, and the `data` it carries. The envelope around `data` is the same for every event (see [Webhooks](https://capacms.com/docs/webhooks)). Subscribe to one type, or to every type of a resource with `instance.*`, `model.*`, `media.*` or `publish.*`.

| Event                                               | When it fires                                                                                                                    |
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| [`instance.created`](#instancecreated)              | An entry was created. Fires for drafts too, before anything is published.                                                        |
| [`instance.updated`](#instanceupdated)              | An entry was saved without being published. A new draft version exists.                                                          |
| [`instance.published`](#instancepublished)          | An entry went live. Turn on Include content data to receive the published fields with it.                                        |
| [`instance.unpublished`](#instanceunpublished)      | An entry was taken off the live API. It still exists as a draft.                                                                 |
| [`instance.deleted`](#instancedeleted)              | An entry was deleted. Use this to drop it from a cache or an index.                                                              |
| [`model.created`](#modelcreated)                    | A model was created.                                                                                                             |
| [`model.updated`](#modelupdated)                    | A model's fields changed. The payload names the fields added, edited and removed so a generated client knows what to rebuild.    |
| [`model.published`](#modelpublished)                | A model version went live, so the public schema changed.                                                                         |
| [`model.deleted`](#modeldeleted)                    | A model was deleted. Its entries go with it and do not send their own events.                                                    |
| [`media.uploaded`](#mediauploaded)                  | A file finished uploading and has a URL.                                                                                         |
| [`media.updated`](#mediaupdated)                    | A file was renamed, moved between folders, or made public or private.                                                            |
| [`media.deleted`](#mediadeleted)                    | A file was deleted. Its URL stops resolving.                                                                                     |
| [`publish.scheduled`](#publishscheduled)            | Somebody scheduled a publish or an unpublish for later.                                                                          |
| [`publish.rescheduled`](#publishrescheduled)        | A scheduled publish moved to a different time.                                                                                   |
| [`publish.cancelled`](#publishcancelled)            | A scheduled publish was cancelled before it ran.                                                                                 |
| [`publish.failed`](#publishfailed)                  | A scheduled publish gave up. Fires once, on the last attempt, never on a retry that is still coming.                             |
| [`publish.batch.completed`](#publishbatchcompleted) | A bulk publish or unpublish finished. Fires once per run, whether it published 2 entries or 500, and never for a single Publish. |
| [`webhook.test`](#webhooktest)                      | Sent only by Send test, and only to the endpoint you sent it from. It is not a subscription.                                     |

## Content

### `instance.created`

An entry was created. Fires for drafts too, before anything is published.

```json
{
  "data": {
    "instanceId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20",
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "namespace": "blog_post",
    "title": "Summer Guide",
    "versionId": "b7d4e2f1-3a5c-4e6b-8d9f-0a1b2c3d4e5f",
    "versionNumber": 4,
    "status": "draft",
    "publishedVersionId": null,
    "publishedAt": null
  }
}
```

### `instance.updated`

An entry was saved without being published. A new draft version exists.

```json
{
  "data": {
    "instanceId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20",
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "namespace": "blog_post",
    "title": "Summer Guide",
    "versionId": "b7d4e2f1-3a5c-4e6b-8d9f-0a1b2c3d4e5f",
    "versionNumber": 4,
    "status": "draft",
    "publishedVersionId": null,
    "publishedAt": null
  }
}
```

### `instance.published`

An entry went live. Turn on Include content data to receive the published fields with it.

Ticked for a new endpoint.

```json
{
  "data": {
    "instanceId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20",
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "modelNamespace": "blog_post",
    "versionId": "b7d4e2f1-3a5c-4e6b-8d9f-0a1b2c3d4e5f",
    "versionNumber": 4,
    "publishedAt": "2026-09-22T14:03:11.000Z",
    "title": "Summer Guide",
    "scheduledActionId": null
  }
}
```

### `instance.unpublished`

An entry was taken off the live API. It still exists as a draft.

Ticked for a new endpoint.

```json
{
  "data": {
    "instanceId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20",
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "modelNamespace": "blog_post",
    "previousVersionId": "b7d4e2f1-3a5c-4e6b-8d9f-0a1b2c3d4e5f",
    "scheduledActionId": null
  }
}
```

### `instance.deleted`

An entry was deleted. Use this to drop it from a cache or an index.

Ticked for a new endpoint.

```json
{
  "data": {
    "instanceId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20",
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "namespace": "blog_post",
    "title": "Summer Guide",
    "deletedAt": "2026-09-22T14:09:40.000Z"
  }
}
```

## Models

### `model.created`

A model was created.

```json
{
  "data": {
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "namespace": "blog_post",
    "modelName": "Blog Post",
    "versionId": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
    "versionNumber": 7,
    "status": "draft"
  }
}
```

### `model.updated`

A model's fields changed. The payload names the fields added, edited and removed so a generated client knows what to rebuild.

```json
{
  "data": {
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "namespace": "blog_post",
    "modelName": "Blog Post",
    "versionId": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
    "versionNumber": 7,
    "fields": {
      "added": [
        "subtitle"
      ],
      "edited": [
        "title"
      ],
      "removed": [
        "legacy_slug"
      ]
    }
  }
}
```

### `model.published`

A model version went live, so the public schema changed.

```json
{
  "data": {
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "modelNamespace": "blog_post",
    "modelName": "Blog Post",
    "versionId": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
    "scheduledActionId": null
  }
}
```

### `model.deleted`

A model was deleted. Its entries go with it and do not send their own events.

```json
{
  "data": {
    "modelId": "2c8b0a11-7f4e-4d2a-9c31-51a2b3c4d5e6",
    "namespace": "blog_post",
    "modelName": "Blog Post"
  }
}
```

## Media

### `media.uploaded`

A file finished uploading and has a URL.

```json
{
  "data": {
    "fileId": "41a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
    "name": "cover.jpg",
    "key": "tenants/acme/cover.jpg",
    "type": "image/jpeg",
    "url": "https://cdn.example.com/tenants/acme/cover.jpg",
    "filesize": 184320,
    "folderId": null,
    "isPublic": false
  }
}
```

### `media.updated`

A file was renamed, moved between folders, or made public or private.

```json
{
  "data": {
    "fileId": "41a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
    "name": "cover.jpg",
    "key": "tenants/acme/cover.jpg",
    "type": "image/jpeg",
    "url": "https://cdn.example.com/tenants/acme/cover.jpg",
    "filesize": 184320,
    "folderId": null,
    "isPublic": true
  }
}
```

### `media.deleted`

A file was deleted. Its URL stops resolving.

```json
{
  "data": {
    "fileId": "41a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
    "name": "cover.jpg",
    "key": "tenants/acme/cover.jpg",
    "type": "image/jpeg",
    "url": "https://cdn.example.com/tenants/acme/cover.jpg"
  }
}
```

## Publishing

### `publish.scheduled`

Somebody scheduled a publish or an unpublish for later.

```json
{
  "data": {
    "actionId": "6d5c4b3a-2918-4f7e-8d6c-5b4a39281706",
    "batchId": "1a2b3c4d-5e6f-4071-8293-a4b5c6d7e8f9",
    "action": "publish",
    "targetType": "instance",
    "targetId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20",
    "runAt": "2026-09-23T13:00:00.000Z",
    "timezone": "America/New_York",
    "wallTime": "2026-09-23T09:00"
  }
}
```

### `publish.rescheduled`

A scheduled publish moved to a different time.

```json
{
  "data": {
    "actionId": "6d5c4b3a-2918-4f7e-8d6c-5b4a39281706",
    "runAt": "2026-09-24T13:00:00.000Z",
    "timezone": "America/New_York",
    "wallTime": "2026-09-24T09:00"
  }
}
```

### `publish.cancelled`

A scheduled publish was cancelled before it ran.

```json
{
  "data": {
    "actionId": "6d5c4b3a-2918-4f7e-8d6c-5b4a39281706",
    "batchId": "1a2b3c4d-5e6f-4071-8293-a4b5c6d7e8f9",
    "targetId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20"
  }
}
```

### `publish.failed`

A scheduled publish gave up. Fires once, on the last attempt, never on a retry that is still coming.

```json
{
  "data": {
    "actionId": "6d5c4b3a-2918-4f7e-8d6c-5b4a39281706",
    "batchId": "1a2b3c4d-5e6f-4071-8293-a4b5c6d7e8f9",
    "action": "publish",
    "targetType": "instance",
    "targetId": "8f1c1f8e-6d3a-4a9e-9a3b-2f0a6b7c1d20",
    "attempts": 5,
    "status": "dead",
    "errorCode": "version_not_found",
    "message": "The version this action was pinned to no longer exists."
  }
}
```

### `publish.batch.completed`

A bulk publish or unpublish finished. Fires once per run, whether it published 2 entries or 500, and never for a single Publish.

```json
{
  "data": {
    "batchId": "1a2b3c4d-5e6f-4071-8293-a4b5c6d7e8f9",
    "action": "publish",
    "targetType": "instance",
    "total": 500,
    "done": 497,
    "failed": 2,
    "dead": 1,
    "cancelled": 0,
    "requestedBy": "00000000-0000-4000-8000-000000000042",
    "completedAt": "2026-09-22T14:05:11.000Z"
  }
}
```

## Test

### `webhook.test`

Sent only by Send test, and only to the endpoint you sent it from. It is not a subscription.

```json
{
  "data": {
    "endpointId": "c3d4e5f6-a7b8-4901-9234-5678abcdef01",
    "message": "Test event from Capa"
  }
}
```
