Workflow Extensions Overview

Overview

HubSpot Workflows is a powerful tool for automating work on HubSpot CRM objects, but also for automating work between HubSpot and other services on the Internet. Another option to do this is the Webhook action, but it can require a lot of repeated, manual setup and knowledge about APIs for the end user to understand. Furthermore, its capability is limited to sending the enrolled object JSON as-is.

Workflow Extensions provide a seamless experience automating work between HubSpot and other services. Rather than exposing URLs, HTTP methods and auth headers to the end user, Workflow Extensions abstract all of these details away. Instead of starting with a non-descript webhook action, HubSpot users can easily find custom workflow actions for your integration in their list of workflow actions. Users can configure the extension in a different way each time they add it to one of their workflows. Because Workflows presents the extension to the user according to a flexible schema pre-defined for each extension, the experience is that of truly custom workflow actions.

Example use case

Suppose for example 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, but then the workflow user has the 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.

Steps to using Workflow Extensions

  1. To get started, you must have a HubSpot Developer account and your own HubSpot application.
    The information you need from your developer portal is your application’s app ID and your Developer HAPIkey. For reasons described below we strongly recommend creating a separate HubSpot application for testing purposes. This test application shouldn't be installed in real users' accounts.
  2. Create the definition for your extension using the new extension definitions API as described in this guide.
  3. Make sure users of the new workflow extension have your integration installed in the HubSpot portal where Workflows are used. At that point, they’ll immediately see your extension available in the Workflows tool. For this reason, starting by developing with a test application will prevent users from being exposed to anything other than your finished custom actions.

Definitions

An extension definition contains all the information needed for Workflows to display the form containing options for the extension. 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 integration’s app ID that will be 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 workflow 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.

Field metadata

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.

Field types

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

Value definitions

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 definition types

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.

Workflow Extension Definition API Reference

When making requests to the extension definition API, take care to use the correct hapikey query parameter. This should be the hapikey from the developer portal with your integration.

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.

Create a new definition

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.

Fetch a workflow extension definition

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
                }
            ]
        }

    ]
}

Fetch all workflow extension definitions for an application

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. It doesn't include any 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
                    }
                ]
            }
         ]
    }
]

Update a workflow extension definition

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 a workflow extension definition

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.

Executing workflow extensions

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.

Customizing the request metadata.

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.

Handling requests

Every extension action HTTP request will contain several facts to help 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.

Example extension action request payload

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

Handling responses

When a response is received by HubSpot, there are three possible outcomes.

  • Any successful response status code (2xx) - The workflow logs a success message in the workflow history and continues with the next action.
  • Rate limit/retry status code (429) - The workflow will retry the action until another response is obtained using an exponential backing off schedule over minutes or hours. If the Retry-After header value in the form of seconds is provided, that value will be used to schedule the next attempt.
  • Any other response status code - The workflow logs a failure message in the workflow history and continues with the next action.

Any data included in the response payload are disregarded, so it’s not necessary to include a response payload.

External Data Fetch Examples

Fetch Request

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
}

Fetch Response

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.

FAQ:

  • What happens when I update an extension definition?
    • If users have started using your custom workflow actions, they remain unchanged. This means that updates to your extension do not retroactively update workflows using the old extension definitions and those workflows will continue to fire requests using the old URL and payload structure. For users to upgrade to the new version, they must create new actions in their workflows after you’ve made changes to the definition.
  • Do Workflow Extensions support Deal, Ticket, or other types of automation?
    • Currently only Contact-based workflows can contain workflow extension actions.
  • Can the workflow wait until an asynchronous process is completed before continuing in the workflow?
    • Asynchronous actions are currently not supported in workflows.
  • Can I set up Workflow Extensions to only be available to some of my integration users?
    • Currently the extensions you create will be available to all users with the associated integration installed and there is no way to give more granular access to different payment tiers, etc.

Docs for this section or API