Skip to main content
The subscriptions API allows you to manage event subscriptions for your app. Additional endpoints also allow you to create snapshots of CRM objects at specific points in time, or filter the events that you’re subscribed to.

Before you get started

You’ll need to generate a client credentials token to use the webhook management API. More information on how to generate this token is available in the authentication section of overview article.

Create and manage subscriptions

The sections below provide details on how to create and manage webhook subscriptions.

Create or update a subscription

To create a new subscription, first ensure your client credentials token was generated with the developer.webhooks_journal.subscriptions.write scope specified. Then make a POST request to /webhooks-journal/subscriptions/2026-03. In the body of your request, include the properties for the subscription you want to create, detailed in the table below.
FieldTypeDescription
objectTypeIdStringThe object type identifier (e.g., "0-1" for contacts). Required for OBJECT and ASSOCIATION subscriptions, but not applicable for LIST_MEMBERSHIP subscriptions.
subscriptionType StringType of subscription. Available types are: OBJECT, ASSOCIATION, APP_LIFECYCLE_EVENT, or LIST_MEMBERSHIP.
portalId NumberThe ID of the HubSpot account to subscribe to events for.
actions ArrayA list of actions to subscribe to. The following actions are available for OBJECT subscriptions:
  • CREATE: Object creation events.
  • UPDATE: Object modification events.
  • DELETE: Object deletion events.
  • MERGE: Object merge events.
  • RESTORE: Object restoration events.
  • ASSOCIATION_ADDED: association creation events.
  • ASSOCIATION_REMOVED: association removal events.
  • SNAPSHOT: snapshot generation.


The following actions are available for LIST_MEMBERSHIP subscriptions:
  • ADDED_TO_LIST: object added to list events.
  • REMOVED_FROM_LIST: object removed from list events.
propertiesArraySpecific properties to include in events. Applies to OBJECT subscription events only.
objectIdsArraySpecific object IDs to subscribe to. Applies to both OBJECT and LIST_MEMBERSHIP subscriptions.
associatedObjectTypeIdsArrayAssociated object types to include. Applies to ASSOCIATION subscriptions only.
listIdsArraySpecific list IDs to monitor for membership changes. If empty or omitted, the subscription will apply to all lists. Applies to LIST_MEMBERSHIP subscriptions only.
The following code example shows how to create 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.
{
  "objectTypeId": "0-1",
  "subscriptionType": "OBJECT",
  "portalId": 12345,
  "actions": ["CREATE", "UPDATE", "DELETE"],
  "properties": ["email", "firstname", "lastname"],
  "objectIds": [1001, 1002, 1003]
}
The resulting response would be:
{
  "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:
{
  "objectTypeId": "0-1",
  "subscriptionType": "ASSOCIATION",
  "portalId": 12345,
  "actions": ["ASSOCIATION_ADDED", "ASSOCIATION_REMOVED"],
  "objectIds": [1001, 1002, 1003],
  "associatedObjectTypeIds": ["0-2"]
}
The corresponding response would be:
{
  "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"
}
The following code block shows how to create a LIST_MEMBERSHIP subscription, which will trigger whenever records are added to or removed from specific lists. If you provide an empty array for the listIds property or omit it entirely, the subscription will apply to all lists:
{
  "subscriptionType": "LIST_MEMBERSHIP",
  "portalId": 12345,
  "actions": [
    "ADDED_TO_LIST",
    "REMOVED_FROM_LIST"
  ],
  "listIds": [101, 102, 103],
  "objectIds": []
  }
}
The resulting response would resemble the following:
{
  "id": 790,
  "appId": 456,
  "subscriptionType": "LIST_MEMBERSHIP",
  "portalId": 12345,
  "actions": ["ADDED_TO_LIST", "REMOVED_FROM_LIST"],
  "listIds": [101, 102, 103],
  "objectIds": [],
  "createdBy": 999,
  "createdAt": "2024-01-01T11:00:00Z",
  "updatedAt": "2024-01-01T11:00:00Z",
  "deletedAt": null
}

Create an app install or uninstall event subscription

To subscribe to app install or app uninstall events, use your client credentials token to make a POST request to /webhooks-journal/subscriptions/2026-03 with the following request body:
{
  "subscriptionType": "APP_LIFECYCLE_EVENT",
  "eventTypeId": "4-1909196",
  "properties": ["string"]
}
You can then retrieve journal events and any app install or uninstall events will be returned in the response. 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/2026-03. The response will resemble the following:
{
  "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 a 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/2026-03/{subscriptionId}. For example, if the ID of the subscription you want to delete is 789, you’d make a DELETE request to https://api.hubapi.com/webhooks-journal/subscriptions/2026-03/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/2026-03/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.

Subscription filters

Subscription filters allow you to attach additional filtering criteria to an existing subscription, further narrowing which events are written to the journal. If you omit filters, then all events matching the subscription criteria will be delivered. Multiple filters can be specified for a subscription. An event is delivered when it satisfies any attached filter (OR logic across filters). Within a single filter, all conditions must be satisfied for the filter to match (AND logic within a filter).

Create a filter

To create a webhook subscription filter, first ensure your client credentials token was generated with the developer.webhooks_journal.subscriptions.write scope specified. Then, make a POST request to /webhooks-journal/subscriptions/2026-03/filters. In the request body, include the subscriptionId that the filter will apply to, along with the filter definition, detailed in the table below.
PropertyTypeDescription
subscriptionIdNumberThe ID of the subscription to attach this filter to.
filter.conditionsArrayArray of conditions (minimum 1). All conditions must match for the filter to pass.
conditions[].filterTypeStringMust be set to "CRM_OBJECT_PROPERTY".
conditions[].property StringThe CRM property name to evaluate (e.g., "lifecycle_stage").
conditions[].operator StringComparison operator. See the filter operators table below.
conditions[].valueStringSingle value for scalar operators (EQ, N_EQ, LT, GT, LTE, GTE, CONTAINS, STARTS_WITH, ENDS_WITH).
conditions[].valuesArrayList of values for set operators (IN, NOT_IN). Must be non-empty.
If you provide an operator of IS_EMPTY or IS_NOT_EMPTY, you should omit value and values from the associated entry in the conditions array.
The examples below provide a JSON request body and associated cURL request to create a filter an existing CRM property change subscription to events where the record’s lifecycle change updated to customer.
{
  "subscriptionId": 12345,
  "filter": {
    "conditions": [
      {
        "filterType": "CRM_OBJECT_PROPERTY",
        "property": "lifecycle_stage",
        "operator": "EQ",
        "value": "customer"
      }
    ]
  }
} 
A successful request will return the ID of the newly created filter:
{
  "filterId": 9876
}
The currently supported filter operators are detailed in the table below:

Filter operators

| Operator | Description | Uses value | Uses values | | --- | --- | --- | --- | --- | | EQ | Property equals value (case-insensitive) | yes | no | | N_EQ | Property does not equal value (case-insensitive) | yes | no | | LT | Property is numerically less than value | yes | no | | GT | Property is numerically greater than value | yes | no | | LTE | Property is numerically less than or equal to value | yes | no | | GTE | Property is numerically greater than or equal to value | yes | no | | IS_EMPTY | Property is absent or empty | no | no | | IS_NOT_EMPTY | Property is present and non-empty | no | no | Note the following caveats and validation rules as you build out your filters:
  • Scalar operators (EQ, N_EQ, LT, GT, LTE, GTE, CONTAINS, STARTS_WITH, ENDS_WITH) require exact value.
  • When using null-check operators (IS_EMPTY and IS_NOT_EMPTY), omit the value and values in the associated entry of your conditions array.
  • Sending both value and values, or omitting both when one is required, will return a validation error.

Retrieve a filter

To get an existing filter by its ID, ensure your client credentials token was generated with the developer.webhooks_journal.subscriptions.read scope specified. Then make a GET request to /webhooks-journal/subscriptions/2026-03/filters/{filterId}. The response will resemble the following:
{
  "id": 9876,
  "filter": {
    "conditions": [
      {
        "filterType": "CRM_OBJECT_PROPERTY",
        "property": "lifecycle_stage",
        "operator": "EQ",
        "value": "customer"
      }
    ]
  },
  "createdAt": 1710710400000
}

Get filters by subscription

To retrieve all filters attached to a specific webhook subscription, first ensure your client credentials token was generated with the developer.webhooks_journal.subscriptions.read scope specified. Then, make a GET request to /webhooks-journal/subscriptions/2026-03/filters/subscription/{subscriptionId}. The response will include an array of filter objects, or an empty array if no filters are attached to the provided subscription ID.
[
  {
    "id": 9876,
    "filter": {
      "conditions": [
        {
          "filterType": "CRM_OBJECT_PROPERTY",
          "property": "lifecycle_stage",
          "operator": "EQ",
          "value": "customer"
        }
      ]
    },
    "createdAt": 1710710400000
  },
  {
    "id": 9877,
    "filter": {
      "conditions": [
        {
          "filterType": "CRM_OBJECT_PROPERTY",
          "property": "email",
          "operator": "IS_NOT_EMPTY"
        }
      ]
    },
    "createdAt": 1710710500000
  }
]

Update a filter

Updating a filter is not currently supported. You’ll need to retrieve an existing filter, make any manual modifications to the JSON definition, then create a new filter with the updated definition. You can then delete the previous filter if it’s unused.

Delete a filter

To delete a filter by its ID, first ensure your client credentials token was generated with the developer.webhooks_journal.subscriptions.write scope specified. Then, make a GET request to /webhooks-journal/subscriptions/2026-03/filters/{filterId}. A successful request will result in a response of 204 No Content, and events will no longer be evaluated against the deleted filter.

Common errors

Consult the table below for errors you might encounter when creating webhook subscription errors:
ErrorDescription
SUBSCRIPTION_NOT_FOUNDThe subscriptionId does not exist or belongs to a different app.
FILTER_NOT_FOUNDThe filterId does not exist or belongs to a different app.
FILTER_INVALID_OPERATORUnsupported operator used
FILTER_PROPERTY_BLANKProperty is null/empty/whitespace
FILTER_PROPERTY_TOO_LONGCondition Property Name > 256 characters
FILTER_UNSUPPORTED_TYPEType isn’t supported
FILTER_CONDITIONS_LIMIT_EXCEEDEDToo many conditions on a filter
FILTER_LIMIT_EXCEEDEDToo many filters on a subscription
FILTER_PROPERTY_VALUE_TOO_LONGCondition value exceeded 256 characters
FILTER_UNSUPPORTED_SUBSCRIPTION_ACTIONFilters on a non-CREATE/UPDATE subscription

Rate limits

The following limits apply to the management and snapshot APIs:
  • Subscription management APIs: subject to a limit of 50 requests per second per app.
  • Snapshot APIs: subject to a limit of 10 requests per second per app.
Learn more about the related rate limits for the journal APIs here.

Next steps

After you’ve familiarized yourself with the webhook management endpoints, check out the API guide on how to use the webhooks journal to retrieve event data for your subscriptions.
Last modified on April 14, 2026