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

# Webhook CRM snapshots API (2027-03-beta)

> Learn how to use the latest version of the webhook CRM snapshot APIs (2027-03-beta).

> [!WARNING]
>
> This functionality is currently in beta. By participating in this beta, you agree to HubSpot's [Developer Terms](https://legal.hubspot.com/developer-terms) and [Developer Beta Terms](https://legal.hubspot.com/developerbetaterms). Note that the functionality is still under active development and is subject to change based on testing and feedback.

The snapshots API allows you to trigger snapshots of CRM objects for specific points in time.

To use this API, ensure your [client credentials token](https://developers.hubspot.com/docs/api-reference/2027-03-beta/webhooks-journal/guide.md#authentication-and-scopes) was generated with the `developer.webhooks_journal.snapshots.write` scope specified.

## Create CRM object snapshots

To create snapshots for multiple CRM objects in a single batch request, make a `POST` request to `/webhooks-journal/snapshots/2027-03-beta/crm`. In the request body, include the `snapshotRequests` property with the objects you want to snapshot.

The available properties for this endpoint are listed in the table below. All fields are required.

| Field | Type | Description |
| - | - | - |
| `snapshotRequests` | Array | A list of snapshot request objects. |
| `portalId` | Number | The ID of the HubSpot account where the object exists. |
| `objectId` | Number | The ID of the CRM object to snapshot. |
| `objectTypeId` | String | Object type identifier (e.g., `"0-1"` for contacts). |
| `properties` | Array | Array of property names to include in the snapshot. |

```json JSON theme={null}
{
  "snapshotRequests": [
    {
      "portalId": 12345,
      "objectId": 1001,
      "objectTypeId": "0-1",
      "properties": ["email", "firstname", "lastname", "phone"]
    },
    {
      "portalId": 12345,
      "objectId": 1002,
      "objectTypeId": "0-1",
      "properties": ["email", "company"]
    }
  ]
}
```

```bash cURL theme={null}
curl -X POST \
  https://api.hubapi.com/webhooks-journal/snapshots/2027-03-beta/crm \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "snapshotRequests": [
      {
        "portalId": 12345,
        "objectId": 1001,
        "objectTypeId": "0-1",
        "properties": ["email", "firstname", "lastname", "phone"]
      },
      {
        "portalId": 12345,
        "objectId": 1002,
        "objectTypeId": "0-1",
        "properties": ["email", "company"]
      }
    ]
  }'
```

A successful request will return status tracking IDs for each requested snapshot:

```json highlight={7,13} theme={null}
{
  "snapshotResponses": [
    {
      "portalId": 12345,
      "objectId": 1001,
      "objectTypeId": "0-1",
      "snapshotStatusId": "550e8400-e29b-41d4-a716-446655440000"
    },
    {
      "portalId": 12345,
      "objectId": 1002,
      "objectTypeId": "0-1",
      "snapshotStatusId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
    }
  ]
}

```

You can then use the `snapshotStatusId` from each entry to poll for processing status, as detailed in the section below.

## Get snapshot status

Snapshot processing is asynchronous: when you create a snapshot, you receive a `snapshotStatusId` rather than an immediate result. Poll the status endpoint until `status` reaches a terminal state (`SUCCESS`, `FAILED`, or `EXPIRED`). See [Polling behavior and 404 responses](#polling-behavior-and-404-responses) below for guidance on handling the brief window before a status record becomes available.

To get the status of a snapshot, make a `GET` request to `/webhooks-journal/snapshots/2027-03-beta/crm/status/{snapshotStatusId}`.

For example, assuming a `snapshotStatusId` of `550e8400-e29b-41d4-a716-446655440000`, the corresponding `cURL` command would be:

```shell theme={null}
curl -X GET \
  https://api.hubapi.com/webhooks-journal/snapshots/2027-03-beta/crm/status/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

```

The response will resemble the following:

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "SUCCESS",
  "initiatedAt": 1704067200000,
  "completedAt": 1704067215000
}
```

| Property | Type | Description |
| - | - | - |
| `id` | String | The snapshot status ID. |
| `status` | String | Current processing status. Possible values are:  <ul><li>`PENDING`: the snapshot has been accepted and is queued for processing.</li><li>`IN_PROGRESS`: the snapshot is actively being processed.</li><li>`SUCCESS`: the internal processing of the snapshot completed without errors. The snapshot may appear in the journal a few seconds after `SUCCESS` is set.</li><li>`FAILED`: processing encountered an error. Check `errorCode` for the reason.</li><li>`EXPIRED`: the snapshot was not processed within the allowed window and has been discarded.</li></ul> |
| `errorCode` | String | Machine-readable failure reason. Present only when `status` is `FAILED`. Possible values are:  <ul><li>`TIMEOUT`: processing exceeded the allowed time limit.</li><li>`VALIDATION_ERROR`: the snapshot request contained invalid data (e.g., the object or requested properties do not exist).</li><li>`INTERNAL_ERROR`: an unexpected internal error occurred during processing. </li><li>`PERMISSION_DENIED`: the app does not have permission to access the requested object or properties.</li></ul> |
| `message` | String | Human-readable detail about the status. Present on failure. |
| `initiatedAt` | Number | Unix timestamp (milliseconds) when the snapshot was requested. |
| `completedAt` | Number | Unix timestamp (milliseconds) when processing reached a terminal state. Absent while still pending or in progress. |

## Polling behavior and 404 responses

Snapshot status records are created asynchronously after the snapshot request is accepted. After creating a snapshot, there is a brief window during which polling for its status may return `404 Not Found`. This is expected, since the status record is propagated across regions and will be available to retrieve after a short delay.

> [!NOTE]
>
> A `404` does not mean the snapshot itself failed. The underlying snapshot processing proceeds independently of status record creation. If a status record never appears, check your journal directly, as the snapshot may have completed successfully regardless.

The recommended polling strategy is:

1. After creating snapshots, store each `snapshotStatusId`.
2. Poll `GET /webhooks-journal/snapshots/2027-03-beta/crm/status/{snapshotStatusId}` with exponential backoff (e.g., starting at 1 seconds, capped at 30 seconds).
3. On `404`, treat it as "not yet available" and retry.
4. Stop polling when `status` is `SUCCESS`, `FAILED`, or `EXPIRED`.
5. Enforce a maximum polling duration or attempt count (e.g., 10 minutes / 20 attempts) to avoid infinite loops.
6. If the terminal state is never reached within that window, check your journal directly.
