There's a new version of the HubSpot API
As of November 30, 2022, HubSpot API Keys are being deprecated and are no longer supported. Continued use of HubSpot API Keys is a security risk to your account and data. Your API Keys could be deactivated at any time after Nov. 30th, and we recommend that you migrate to Private Apps as soon as possible so you do not lose business-critical functionality.
HubSpot Workflows is a powerful tool for automating work on HubSpot CRM objects. It can also be used for automating work between HubSpot and other services on the Internet. One option to do this is through a Webhook action, but this can require a lot of repeated, manual setup and knowledge about APIs for the end user to understand. Its capability is also limited to sending the enrolled object JSON as-is.
Workflow Extensions provide a seamless experience for automating work between HubSpot and other services through custom workflow actions. Rather than exposing URLs, HTTP methods, and auth headers to the end user, Workflow Extensions abstract all of these details away. HubSpot users can easily find custom actions created by your app in their standard list of workflow actions. Users can configure the custom action in a different way each time they add it to one of their workflows.
Suppose you have a web service that tracks appointments with clients. You’d like users to have HubSpot Workflows create these appointments automatically. The way each appointment is set up might vary slightly based on the workflow, but you know you’ll want to know the purpose of the appointment, the date requested for the appointment, and some notes about the meeting. A workflow extension can present these options to the Workflows user and remove the need to set up a new configuration in your service.
Here’s how it might look in Workflows:
The Appointment Summary, Requested Appointment Date, and Appointment Notes fields appear in the workflow action according to options you define. The workflow user has the additional flexibility to customize the payload with their object properties and manually entered data.
Each time a contact goes through this custom workflow action, Workflows will send your service a customized HTTP request including the user-entered data and the contact’s ID and properties.
app ID
and your Developer HAPIkey. For reasons described below we strongly recommend creating a separate HubSpot app for testing purposes. This test app shouldn't be installed in real users' accounts.An extension definition contains all the information needed for Workflows to display the form containing options for the custom action. The same extension definition also defines the JSON payload format in the outbound HTTP requests. The following fields may be part of an extension definition:
Field name | Field type | Description |
---|---|---|
integrationAppId | integer | Your app's ID. It will be uniquely associated with the workflow extension. This is required and cannot be changed. |
extensionName | string | The user-facing name of your workflow extension that appears in the available actions list. This is required and cannot be changed. Each definition for a given app ID must have a unique name. |
webhookUrl | string | The URL that will accept an HTTPS POST request each time Workflows executes the extension action. This URL must use HTTPS (i.e. starts with https:// ). This is required. |
fieldMetadata | array | Array of ExtensionFieldMetadata objects, each defining a variable field in the extension. This is required but may be empty. An empty array will present no fields to be completed by users in Workflows. |
dataUrl | string | The URL from which we will fetch external options to display in the action. This URL must use HTTPS (i.e. starts with https:// ). This is not required unless there are one or more EXTERNAL_DATA value definitions in the extension. |
Each field in an extension definition’s fieldMetadata maps to a key-value pair in the outbound request JSON and to a visual component in the action in Workflows.
Field name | Field type | Description |
---|---|---|
key | string | Unique string that identifies the value of this field in a key-value pair in the outbound request payload. |
label | string | User-facing label appearing next to the corresponding interface component in Workflows. |
fieldType | string | Describes the type of data expected by each value definition. Values: DATE, NUMBER, SELECT, TEXT, TEXTAREA, OWNER |
required | boolean | Indicates whether it is an error to omit the field. Users will not be able to create actions missing required fields. Optional, but defaults to true. |
values | array | An array of one or more value definitions that describe how the user should provide a value for this field. Providing multiple value definitions gives the end-user the choice of how to populate the value. For example, the user could enter a value manually OR selecting a property containing the desired value within a single field. If multiple value definitions are used, the user only completes one of the options for the field, but can change it at any time. |
If there is a STATIC_VALUE value definition for the field, the field type determines the input element to display to the end user. If there is an OBJECT_PROPERTY value definition for the field, the field type determines which types of properties to display in the dropdown menu presented to the end user.
Value | Static value input element | Object property types |
---|---|---|
DATE | Date picker | date, datetime |
NUMBER | Number field | number |
SELECT | Dropdown menu | string |
TEXT | Single line text field | string |
TEXTAREA | Multi-line text box | string |
OWNER | Dropdown menu of HubSpot owners | owner |
Field name | Field type | Description |
---|---|---|
type | string | Unique string that identifies the value of this field in a key-value pair in the outbound request payload. Values: STATIC_VALUE, OBJECT_PROPERTY |
allowsMergeTags | boolean | For fields with the TEXT and TEXTAREA fieldType. If enabled, the input element will show a personalization token/merge tag selector. Merge tags included in the text are replaced by their corresponding values at the time the HTTP request payload is created. |
Value | Description |
---|---|
STATIC_VALUE | The field presents a data entry element such as a text input appropriate for the field’s fieldType. Can also be used with SELECT field types to specify options. |
OBJECT_PROPERTY | The field presents a dropdown menu containing HubSpot properties. When the extension is executed, the value contained in the property is used as the value corresponding to the field’s key. |
EXTERNAL_DATA | The field presents options pulled from an external data source specified in the dataUrl. |
When making requests to the extension definition API, take care to use the correct API key in the hapikey
query parameter. This should be the Developer API key from the developer account where your app is defined.
Requests to get, update, or delete existing definitions require an applicationId
query parameter corresponding to the workflow extension’s integration. If this applicationId doesn’t match the integrationAppId
in the extension definition, requests will fail.
POST https://api.hubapi.com/automationextensions/v1/definitions?hapikey=<<hapikey>>&applicationId=<<app ID>>
The payload must include all of the following fields. The app ID and name can not be changed after the extension is created, but you can create as many extension definitions as you like. Each definition for a given app ID must have a unique name.
Example request payload:
{
"integrationAppId": 1162896,
"extensionName": "Create New Appointment",
"webhookUrl": "https://api.myservice.com/hubspot/new-appointment",
"fieldMetadata": [
{
"label": "Appointment Summary",
"key": "appointment_title",
"fieldType": "TEXT",
"values": [
{
"type": "STATIC_VALUE",
"allowsMergeTags": true
}
]
},
{
"label": "Requested Appointment Date",
"key": "appointment_date",
"fieldType": "DATE",
"values": [
{
"type": "OBJECT_PROPERTY"
}
]
},
{
"label": "Appointment Notes",
"key": "appointment_notes",
"fieldType": "TEXTAREA",
"values": [
{
"type": "STATIC_VALUE",
"allowsMergeTags": true
}
]
}
]
}
A successful response payload contains the definition and its generated unique ID and version metadata. The id
field is the extension definition ID used in the path of GET, POST and DELETE requests to manage your workflow extensions. Every change to the definition increments the version
field. Webhook requests from the actions in workflows include the definition version number as part of the request origin metadata since users may have different versions of your custom action in use across their workflows.
GET https://api.hubapi.com/automationextensions/v1/definitions/<<definition id>>?hapikey=<<hapikey>>&applicationId=<<app ID>>
Example response:
{
"extensionName": "Create New Appointment",
"integrationAppId": 1162896,
"id": 108,
"latestVersion": 0,
"version": 0,
"webhookUrl": "https://api.myservice.com/hubspot/new-appointment",
"fieldMetadata": [
{
"label": "Appointment Summary",
"key": "appointment_title",
"fieldType": "TEXT",
"values": [
{
"type": "STATIC_VALUE",
"allowsMergeTags": true
}
]
},
{
"label": "Requested Appointment Date",
"key": "appointment_date",
"fieldType": "DATE",
"values": [
{
"type": "OBJECT_PROPERTY"
}
]
},
{
"label": "Appointment Notes",
"key": "appointment_notes",
"fieldType": "TEXTAREA",
"values": [
{
"type": "STATIC_VALUE",
"allowsMergeTags": true
}
]
}
]
}
GET https://api.hubapi.com/automationextensions/v1/definitions?hapikey=<<hapikey>>&applicationId=<<app ID>>
This endpoint returns all active extension definitions associated with the given app ID. This includes extension definitions that have been deleted.
Example response:
[
{
"extensionName": "Create New Appointment",
"integrationAppId": 1162896,
"id": 108,
"latestVersion": 0,
"version": 0,
"webhookUrl": "https://api.myservice.com/hubspot/new-appointment",
"fieldMetadata": [
{
"label": "Appointment Summary",
"key": "appointment_title",
"fieldType": "TEXT",
"values": [
{
"type": "STATIC_VALUE",
"allowsMergeTags": true
}
]
},
{
"label": "Requested Appointment Date",
"key": "appointment_date",
"fieldType": "DATE",
"values": [
{
"type": "OBJECT_PROPERTY"
}
]
},
{
"label": "Appointment Notes",
"key": "appointment_notes",
"fieldType": "TEXTAREA",
"values": [
{
"type": "STATIC_VALUE",
"allowsMergeTags": true
}
]
}
]
},
{
"extensionName": "My Other Extension",
"integrationAppId": 1162896,
"id": 109,
"latestVersion": 0,
"version": 0,
"webhookUrl": "https://api.myservice.com/hubspot/other-action",
"fieldMetadata": [
{
"label": "Test Field",
"key": "test_field",
"fieldType": "TEXT",
"values": [
{
"type": "STATIC_VALUE",
"allowsMergeTags": true
}
]
}
]
}
]
PUT https://api.hubapi.com/automationextensions/v1/definitions/<<definition id>>?hapikey=<<hapikey>>&applicationId=<<app ID>>
In the following example request payload, we add a field and update the webhookUrl
. The definition ID is required in the update request payload.
{
"extensionName": "Create New Appointment",
"integrationAppId": 1162896,
"id": 108,
"webhookUrl": "https://api.myservice.com/hubspot/new-appointment-v2",
"fieldMetadata": [
{
"key": "appointment_title",
"label": "Appointment Summary",
"values": [
{
"allowsMergeTags": true,
"type": "STATIC_VALUE",
"options": []
}
],
"fieldType": "TEXT"
},
{
"label": "Appointment DRI",
"key": "appointment_dri",
"fieldType": "OWNER",
"values": [
{
"type": "STATIC_VALUE"
}
]
},
{
"key": "appointment_date",
"label": "Requested Appointment Date",
"values": [
{
"type": "OBJECT_PROPERTY"
}
],
"fieldType": "DATE"
},
{
"key": "appointment_notes",
"label": "Appointment Notes",
"values": [
{
"allowsMergeTags": true,
"type": "STATIC_VALUE",
"options": []
}
],
"fieldType": "TEXTAREA"
}
]
}
DELETE https://api.hubapi.com/automationextensions/v1/definitions/<<definition id>>?hapikey=<<hapikey>>&applicationId=<<app ID>>
Deleting a workflow extension definition results in removing it as an option in your users’ workflows. The custom actions that were created remain in the workflows, but contacts enrolled in the workflow will skip those actions.
When a workflow executes an extension action, it constructs an HTTP request according to the options set by the end user. HubSpot signs the request and issues an HTTP POST request to the URL specified.
At this time, every HTTP request made for a workflow extension will share the exact same URL. Therefore it’s not possible to customize the path or query parameters. Custom header values are also not supported at this time.
Note: Requests made for Workflow Extensions use the v2 version of the X-HubSpot-Signature header. Please see this page for more details on validating this version of the signature, and this page for more details about validating requests in general.
Every extension action HTTP request will contain several components that can be used to verify its origin.
First, an X-HubSpot-Signature
header value is set in the way documented here: https://developers.hubspot.com/docs/faq/validating-requests-from-hubspot
To understand which account or user and which extension the request relates to, check the origin
object included in the request payload. It includes the HubSpot portalId
, extensionDefinitionId
, and extensionDefinitionVersionId
.
Using the example workflow extension described in this guide, an example webhook payload would look like the following:
{
"fields": {
"appointment_date": "1536019200000",
"appointment_notes": "30 minute appointment to go over the services contract",
"appointment_title": "Appointment with Sky"
},
"object": {
"objectId": 34,
"objectType": "CONTACT"
},
"origin": {
"extensionDefinitionId": 108,
"extensionDefinitionVersionId": 5,
"portalId": 99160967
}
}
When a response is received by HubSpot, there are three possible outcomes:
Any data included in the response payload are disregarded, so it’s not necessary to include a response payload.
A data fetch request includes the HubSpot portalId
, extensionDefinitionId
, and extensionDefinitionVersionId
.
A request for the example extension defined above would be a POST request to the dataUrl
with the following payload:
{
"portalId":99160967,
"extensionDefinitionId":108,
"extensionDefinitionVersion":5
}
The expected response to a data fetch request includes an options
object containing an entry for each definition field for which data is fetched. Each field is map of display text to its internal value. An example response body to a fetch request would be:
{
"options": {
"field-key1":{
"display1":"value1",
"display2":"value2"
},
"field-key2":{
"display3":"value3",
"display4":"value4"
}
}
}
Using this response, Workflows will populate the field with dropdown options "display1" and "display2" for field-key1
, and "display3" and "display4" for field-key2
. The values used when constructing the request for each action will correspond to the user's choice, e.g. value1
, value2
, etc.