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

---
id: 012ed8ab-3865-4c19-8cba-561f3a6cb4b4
---

# Webhooks journal and management APIs (BETA)

> Learn how to use the new webhooks journal and v4 management APIs.

This guide provides guidance for the HubSpot Webhooks Journal system and the latest version (v4) of the webhooks subscription API. The webhooks journal API enables third-party integrators to subscribe to real-time events, retrieve historical event data, and manage snapshots of CRM objects, and the webhooks v4 API builds on the previous version of the webhooks subscription API.

<Warning>
  **Please note:** these APIs provide a new subscription model and are <u>not</u> currently compatible with the previous version (v3) of the webhooks API:

  <ul>
    <li> The webhooks journal and management functionality described in this guide are managed by API only because they are install-specific, and don't work with the feature component functionality described in [this article](/apps/developer-platform/add-features/configure-webhooks).</li>
    <li> The webhooks v4 endpoints do not include a `targetUrl` field, as the subscriptions are written to the journal that's polled by the app.</li>
  </ul>
</Warning>

## Authentication

All API endpoints require OAuth 2.0 authentication. The webhooks journal API uses a client credentials token to authorize actions on behalf of your app. Instructions for setting up this token can be found in the [authentication overview](/apps/developer-platform/build-apps/authentication/overview#client-credentials).

A successful request to the `https://api.hubapi.com/oauth/v1/token` endpoint will then return an access token you can include in the `Authorization` header of your requests:

```http theme={null}
Authorization: Bearer YOUR_ACCESS_TOKEN
```

### Required scopes

You'll need to authorize the following scopes based on the webhook management and journal endpoints you're planning on using:

* `developer.webhooks_journal.read`: access journal data.
* `developer.webhooks_journal.subscriptions.read`: retrieve subscription information.
* `developer.webhooks_journal.subscriptions.write`: create, update, and delete subscriptions.
* `developer.webhooks_journal.snapshots.read`: retrieve snapshot information.
* `developer.webhooks_journal.snapshots.write`: create and manage object snapshots.

In addition to the management scopes above, you'll also need to authorize any scopes that correspond to the object types you're planning on subscribing to. For example, if you plan on subscribing to contact change events, you'll need to authorize the `crm.contacts.read` scope.

A full list of available scopes in [this reference article](/apps/developer-platform/build-apps/authentication/scopes).

## Webhooks journal API

The Journal API provides access to historical event data stored in chronological order. This API allows you to query for changes that occurred for your subscriptions for the past 3 days. These endpoints are optimized to provide a performant response to check the corresponding data that changed for an object or property that you're subscribed to, especially compared to the alternative of using the [CRM search API](/api-reference/legacy/crm/search-the-crm).

### Get earliest journal entry

To retrieve the earliest available journal entry for your app, ensure your app has the `developer.webhooks_journal.read` scope, then make a `GET` request to `/webhooks-journal/journal/v4/earliest`.

The response will resemble the following:

```json theme={null}
{
  "url": "https://s3.amazonaws.com/bucket/path/to/journal/file.json",
  "expiresAt": "2024-01-01T12:00:00Z",
  "currentOffset": "550e8400-e29b-41d4-a716-446655440000"
}
```

You can then retrieve the file at the specified `url` in the response for the associated journal data.

### Get latest journal entry

To retrieve the latest available journal entry for your app, ensure your app has the `developer.webhooks_journal.read` scope, then make a `GET` request to `/webhooks-journal/journal/v4/latest`.

The response will resemble the following:

```json theme={null}
{
  "url": "https://s3.amazonaws.com/bucket/path/to/journal/file.json",
  "expiresAt": "2024-01-01T12:00:00Z",
  "currentOffset": "550e8400-e29b-41d4-a716-446655440000"
}
```

You can then retrieve the file at the specified `url` in the response for the associated journal data.

### Get next journal entry

To retrieve the next journal entry after a specific offset, authorize the `developer.webhooks_journal.read` scope for your app, then make a `GET` request to `/webhooks-journal/journal/v4/offset/{offset}/next`. The `offset` path parameter is the UUID offset from the previous journal entry.

For example, using the response from the previous sections, you'd then make a `GET` request to `/webhooks-journal/journal/v4/offset/550e8400-e29b-41d4-a716-446655440000/next`.

The code block below demonstrates an example response.

```json theme={null}
{
  "url": "https://s3.amazonaws.com/bucket/path/to/journal/file.json",
  "expiresAt": "2024-01-01T12:00:00Z",
  "currentOffset": "550e8400-e29b-41d4-a716-446655440000"
}
```

You can then retrieve the file at the specified `url` in the response for the associated journal data.

## Subscriptions v4 API

The subscriptions API allows you to manage event subscriptions for your app.

### Create or update subscriptions

To create a new subscription, authorize the `developer.webhooks_journal.subscriptions.write` scope for your app, then make a `POST` request to `/webhooks-journal/subscriptions/v4`. In the body of your request, include the properties for the subscription you want to create, detailed in the table below.

<p className="table-key">
  Fields marked with <span style={{ color: 'red' }}>\*</span> are required.
</p>

| Field                                                    | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| -------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `objectTypeId` <span style={{color:"red"}}>\*</span>     | String | The object type identifier (e.g., `"0-1"` for contacts).                                                                                                                                                                                                                                                                                                                                                                                                              |
| `subscriptionType` <span style={{color:"red"}}>\*</span> | String | Type of subscription: `"OBJECT"` or `"ASSOCIATION"`.                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `portalId` <span style={{color:"red"}}>\*</span>         | Number | The ID of the HubSpot account to subscribe to events for.                                                                                                                                                                                                                                                                                                                                                                                                             |
| `actions` <span style={{color:"red"}}>\*</span>          | Array  | A list of actions to subscribe to. The following actions are available: <ul><li>`CREATE`: Object creation events.</li><li>`UPDATE`: Object modification events.</li><li>`DELETE`: Object deletion events.</li><li>`MERGE`: Object merge events.</li><li>`RESTORE`: Object restoration events.</li><li>`ASSOCIATION_ADDED`: association creation events.</li><li>`ASSOCIATION_REMOVED`: association removal events.</li><li>`SNAPSHOT`: snapshot generation.</li></ul> |
| `properties`                                             | Array  | Specific properties to include in events.                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `objectIds`                                              | Array  | Specific object IDs to subscribe to.                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `associatedObjectTypeIds`                                | Array  | Associated object types to include.                                                                                                                                                                                                                                                                                                                                                                                                                                   |

The following code example provides an example of creating a subscription with a `subscriptionType` of `OBJECT` to subscribe to creation and deletion events for a set of specific contacts, as well as any updates to the email, first name, or last name properties of those contacts. Note that the `portalId` property specifies the ID of the HubSpot account to subscribe to the corresponding subscription type.

<CodeGroup>
  ```json JSON theme={null}
  {
    "objectTypeId": "0-1",
    "subscriptionType": "OBJECT",
    "portalId": 12345,
    "actions": ["CREATE", "UPDATE", "DELETE"],
    "properties": ["email", "firstname", "lastname"],
    "objectIds": [1001, 1002, 1003]
  }
  ```

  ```bash cURL theme={null}
  curl -X POST \
    https://api.hubapi.com/webhooks-journal/subscriptions/v4 \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "objectTypeId": "0-1",
      "subscriptionType": "OBJECT",
      "portalId": 12345,
      "actions": ["CREATE", "UPDATE"],
      "properties": ["email", "firstname", "lastname"]
    }'
  ```
</CodeGroup>

The resulting response would be:

```json theme={null}
{
  "id": 789,
  "appId": 456,
  "subscriptionType": "OBJECT",
  "objectTypeId": "0-1",
  "portalId": 12345,
  "actions": ["CREATE", "UPDATE", "DELETE"],
  "properties": ["email", "firstname", "lastname"],
  "objectIds": [1001, 1002, 1003],
  "createdBy": 999,
  "createdAt": "2024-01-01T10:00:00Z",
  "updatedAt": "2024-01-01T10:00:00Z",
  "deletedAt": null
}
```

The following code snippet demonstrates how to create a subscription with a `subscriptionType` of `ASSOCIATION`, which will trigger any time a set of specific contacts (provided via the `objectIds` field) are associated with a company, or if any existing associations are removed:

```json theme={null}
{
  "objectTypeId": "0-1",
  "subscriptionType": "ASSOCIATION",
  "portalId": 12345,
  "actions": ["ASSOCIATION_ADDED", "ASSOCIATION_REMOVED"],
  "objectIds": [1001, 1002, 1003],
  "associatedObjectTypeIds": ["0-2"]
}
```

The corresponding response would be:

```json theme={null}
{
  "id": 60001005,
  "appId": 936515,
  "subscriptionType": "ASSOCIATION",
  "objectTypeId": "0-1",
  "portalId": 12345,
  "actions": ["ASSOCIATION_REMOVED", "ASSOCIATION_ADDED"],
  "objectIds": [1001, 1002, 1003],
  "createdAt": "2025-07-10T18:30:38.062Z",
  "updatedAt": "2025-07-10T18:30:38.062Z"
}
```

### Create an app install or uninstall event subscription

To subscribe to app install or app uninstall events, use your [client credentials token](/apps/developer-platform/build-apps/authentication/overview#client-credentials) to make a `POST` request to `/webhooks-journal/subscriptions/v4` with the following request body:

```json theme={null}
{
  "subscriptionType": "APP_LIFECYCLE_EVENT",
  "eventTypeId": "4-1909196",
  "properties": ["string"]
}
```

You can then [retrieve journal events](#webhooks-journal-api) and any app install or uninstall events will be returned in the [response](#app-install-and-uninstall-event-journal-payloads).

Note that the following event type IDs (`eventTypeId`) are available based on the event you want to subscribe to:

* `4-1909196`: App install event
* `4-1916193`: App uninstall event

### Get all subscriptions

To retrieve all subscriptions, authorize the `developer.webhooks_journal.subscriptions.read` scope for your app, then make a `GET` request to `/webhooks-journal/subscriptions/v4`.

The response will resemble the following:

```json theme={null}
{
  "results": [
    {
      "id": 789,
      "appId": 456,
      "subscriptionType": "OBJECT",
      "objectTypeId": "0-1",
      "portalId": 12345,
      "actions": ["CREATE", "UPDATE"],
      "properties": ["email", "firstname", "lastname"],
      "objectIds": [],
      "associatedObjectTypeIds": [],
      "createdBy": 999,
      "createdAt": "2024-01-01T10:00:00Z",
      "updatedAt": "2024-01-01T10:00:00Z",
      "deletedAt": null
    }
  ]
}
```

### Delete subscription

To delete a specific subscription by its ID, authorize the `developer.webhooks_journal.subscriptions.write` scope for your app, then make a `DELETE` request to `/webhooks-journal/subscriptions/v4/{subscriptionId}`. You can retrieve a list of subscriptions by following the steps in the sections above, then use the ID for one of the entries in the response to delete it using this endpoint.

For example, if the ID of the subscriptions you want to delete is `789`, you'd make a `DELETE` request to `https://api.hubapi.com/webhooks-journal/subscriptions/v4/789`.

A successful request will result in a response of `204 No Content`.

### Delete all subscriptions for an account

To delete all subscriptions for a specific HubSpot account, authorize the `developer.webhooks_journal.subscriptions.write` scope for your app, then make a `DELETE` request to `/webhooks-journal/subscriptions/v4/portals/{portalId}`, using the ID of the HubSpot account as the `portalId` path parameter.

A successful deletion request will return a response of `204 No Content`.

## Snapshots API

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

### Create CRM object snapshots

To create snapshots for multiple CRM objects in a single batch request, ensure you've authorized the `developer.webhooks_journal.snapshots.write` scope, then make a `POST` request to `/webhooks-journal/snapshots/v4/crm`. In the request body, include the `snapshotRequests` property, which should include the snapshots for the objects you want to update.

For example, your request body might resemble the following if you wanted to trigger snapshots for two contacts with two different sets of properties.

<CodeGroup>
  ```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/v4/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"]
        }
      ]
    }'
  ```
</CodeGroup>

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

A successful request will return a response of `204 No Content`.

## Common object type IDs

Here are the standard HubSpot object type IDs you'll use in API requests:

| `objectTypeId` | Object type          |
| -------------- | -------------------- |
| `0-1`          | Contacts             |
| `0-2`          | Companies            |
| `0-3`          | Deals                |
| `0-4`          | Engagements          |
| `0-5`          | Tickets              |
| `0-7`          | Products             |
| `0-8`          | Line Items           |
| `0-11`         | Conversations        |
| `0-14`         | Quotes               |
| `0-15`         | Forms                |
| `0-19`         | Feedback Submissions |
| `0-20`         | Attributions         |
| `0-27`         | Tasks                |
| `0-45`         | Object Lists         |

<Tip>
  **Please note:** object type IDs follow the format `{metaTypeId}-{innerId}`. Standard HubSpot objects use metaTypeId `0`, while custom objects use metaTypeId `2`.
</Tip>

## Event data format

When you retrieve journal files from the URLs provided by the webhooks journal API, the files contain JSON events in the following format:

### Contact creation event example

```json theme={null}
{
  "offset": "0197f5c0-4d9b-7932-83ec-06d56430c359",
  "journalEvents": [
    {
      "type": "crmObject",
      "portalId": 123456,
      "occurredAt": "2025-07-10T19:11:49.524Z",
      "action": "CREATE",
      "objectTypeId": "0-1",
      "objectId": 125119015226
    }
  ],
  "publishedAt": "2025-07-10T19:11:50.172Z"
}
```

### Contact update event example

```json theme={null}
{
  "offset": "0198197a-f0ac-7906-8bfe-a569398704ac",
  "journalEvents": [
    {
      "type": "crmObject",
      "portalId": 145534986,
      "occurredAt": "2025-07-17T17:42:23.540Z",
      "action": "UPDATE",
      "objectTypeId": "2-134027637",
      "objectId": 11073740016,
      "propertyChanges": {
        "pet_name": "Scrappy 4"
      }
    }
  ],
  "publishedAt": "2025-07-17T17:42:24.173Z"
}
```

### Contact update event example

```json theme={null}
{
  "offset": "0197f5c0-4d9b-7932-83ec-06d56430c359",
  "journalEvents": [
    {
      "type": "crmObject",
      "portalId": 123456,
      "occurredAt": "2025-07-10T19:11:49.524Z",
      "action": "UPDATE",
      "objectTypeId": "0-1",
      "objectId": 125119015226,
      "propertyChanges": {
        "lastname": "smith"
      }
    }
  ],
  "publishedAt": "2025-07-10T19:11:50.172Z"
}
```

### Association added example

```json theme={null}
{
  "offset": "0198199f-f454-7ee4-9766-779433c4864d",
  "journalEvents": [
    {
      "type": "association",
      "portalId": 145534986,
      "occurredAt": "2025-07-17T18:22:49.134Z",
      "action": "ASSOCIATION_ADDED",
      "fromObjectId": 11073740013,
      "toObjectId": 11073740016,
      "fromObjectTypeId": "2-134027637",
      "toObjectTypeId": "2-134027637",
      "associationTypeId": 17,
      "associationCategory": "USER_DEFINED",
      "isPrimary": false
    }
  ]
}
```

### App install and uninstall event journal payloads

If you [subscribe to app install and uninstall events](), the corresponding journal events will resemble the following:

```json theme={null}
{
  "offset": "01983883-ee94-71df-8c20-9f3cbf039015",
  "journalEvents": [
    {
      "type": "app_lifecycle_event",
      "occurredAt": "2025-07-23T18:20:23.719Z",
      "action": "APP_INSTALL",
      "portalId": 123456,
      "eventTypeId": "4-1909196",
      "properties": {
        "hs_app_id": 1234567,
        "hs_app_install_level": "PORTAL",
        "hs_initiating_user_id": 987654321,
        "hs_user_id": 12345
      }
    }
  ],
  "publishedAt": "2025-07-23T18:20:27.156Z"
}
```

Note that the following event type IDs (`eventTypeId`) are available based on the triggered event:

* `4-1909196`: App install event
* `4-1916193`: App uninstall event

## Error handling

The API uses standard HTTP status codes to indicate success or failure:

### Success codes

* `200 OK`: request successful
* `204 No Content`: request successful with no response body

### Error codes

* `400 Bad Request`: invalid request parameters
* `401 Unauthorized`: missing or invalid authentication token
* `403 Forbidden`: insufficient permissions for the requested operation
* `404 Not Found`: requested resource not found
* `429 Too Many Requests`: rate limit exceeded
* `500 Internal Server Error`: server error, possibly due to an backend issue from HubSpot

### Error response format

Error responses include details in the following format:

```json theme={null}
{
  "status": "error",
  "message": "Invalid subscription type provided",
  "correlationId": "550e8400-e29b-41d4-a716-446655440000",
  "category": "VALIDATION_ERROR"
}
```

## Rate Limits

The following rate limits apply to the webhook journal and v4 management APIs:

* **Journal API:** 100 requests per second per app
* **Subscriptions API:** 50 requests per second per app
* **Snapshots API:** 10 requests per second per app

When you exceed rate limits, you'll receive a `429 Too Many Requests` response with a `Retry-After` header indicating when you can retry.

<Warning>
  **Please note:** the limits above are subject to change during the current beta period. These rate limits are distinct from the rest of HubSpot's rate limits outlined [here](/developer-tooling/platform/usage-guidelines).
</Warning>

## Best practices

Keep the following best practices when using the webhooks journal API:

### Journal processing

* **Sequential Processing:** Process journal files in chronological order using the offset system
* **Offset Management:** Always store and use the `currentOffset` from responses for pagination
* **URL Expiration:** Journal URLs expire after a set time - download files promptly
* **Error Handling:** Implement exponential backoff for transient errors

### Subscription management

* **Specific Filters:** Use object type and action filters to reduce unnecessary events
* **Property Selection:** Only subscribe to properties you need to minimize data transfer
* **Batch Operations:** Group subscription changes when possible
* **Regular Cleanup:** Remove unused subscriptions to maintain performance

### Snapshot usage

* **Batch Requests:** Group multiple snapshot requests into single API calls
* **Property Optimization:** Only request properties you need for each object
* **Portal Awareness:** Ensure objects exist in the specified portal before requesting snapshots
* **Timing Considerations:** Snapshots reflect object state at request time

### Error handling

* **Retry Logic:** Implement exponential backoff for rate limits and temporary errors
* **Correlation IDs:** Use correlation IDs from error responses when contacting support
* **Validation:** Validate request data before sending to reduce error rates
* **Monitoring:** Monitor API usage and error rates to detect issues early
