There's a new version of the HubSpot API
We're also working on a new documentation website, you're invited to check it out and give us your feedback.
Within a public app, you can create custom CRM cards to display information from other systems on HubSpot contact, company, deal, and ticket records. Each app can include up to 25 CRM cards.
Please note: these cards are different from the custom cards you can create as UI extensions with projects (BETA). The CRM cards included in this article are intended for use with public apps, not private apps created with projects. If you're not building a public app, check out the CRM development tools overview to see if React-based UI extensions will work better for your use case.
Using this API, you can surface data from an integration in cards on CRM records, such as contacts, companies, deals, and tickets. When a HubSpot user views one of these CRM records, HubSpot makes an outbound request, retrieves information for that record, then displays it in a CRM card in the sidebar. In addition to displaying data, integrations can also specify the actions a user will be able to take. This includes opening a modal window and allowing your integration to appear seamlessly inside the HubSpot CRM.
Example use case: you're building an integration for the App Marketplace for your bug tracking software. You want to be able to surface tracked bugs on contact records so that support reps can reference them when working with customers. Your app can define a custom card that displays this info right on the HubSpot contact record.
The whole card is defined by a record type the integrator can specify. Individual items within the card are card properties. The titles for these card properties can optionally be turned into links to the external system. Please note that the "Powered by" line on the card will use the app name from your app settings.
Record types are created within your developer account. On the Apps dashboard, choose the app you want to integrate and go to CRM cards. When a user installs the application, HubSpot will start sending data fetch requests for record types associated with it. (Detailed instructions here.)
The data flow for how card properties show up on the CRM looks like this:
When a user loads the details page for a record in the CRM, HubSpot will send a data fetch request to the integrator. The integrator will respond to this request with the card properties associated with the current CRM object.
In order to use CRM Extensions, you will need to request the appropriate OAuth scopes for any CRM objects that you want to create a card for. This will mean that you need the contacts
scope if you want to set up a card for contacts, companies, or deals, and the tickets
scope if you want to create a card for tickets. See the OAuth documentation for more details about scopes and setting up the authorization URL for your app.
If your integration is already using CRM Extensions, you will not be able to remove the contacts
or tickets
scopes until you delete all of the CRM cards that have been set up for the associated CRM object types.
Object Types show the integrator's intent to provide some objects associated with data in the CRM. Creating an Object Type is the first step in using CRM Extensions.
This section describes the different fields on the record type.
applicationId
: The ID of the application that should own this record type.baseUris
: A list of acceptable base URIs for actions. All action URIs must be located under one of these pathsdataFetchUri
: The URI the CRM will call to fetch data for a given CRM object specified in associatedHubSpotObjectTypes
.title
: The title of this object. This will be displayed as the title of the CRM sidebar card.propertyDefinitions
: The common properties that these objects will have, in the order they should appear on the sidebar card. See Property Types for more info.associatedHubSpotObjectTypes
: A set of CONTACT
, COMPANY
, DEAL
, or TICKET
. This determines where on the CRM this Object Type will appear -- contact, company, deal, or ticket details pages.associatedHubSpotObjectTypeProperties
: HubSpot properties to send in the data fetch request, by CRM Object Type.Example record type:
{ "applicationId": 767676, "baseUris": [ "https://example.com/actions" ], "dataFetchUri": "https://example.com/demo-tickets", "title": "DemoTickets", "propertyDefinitions": [ { "name": "ticket_type", "label": "Ticket type", "dataType": "STRING" }, { "options": [ { "type": "SUCCESS", "label": "In Progress", "name": "inprogress" }, { "type": "DEFAULT", "label": "Resolved", "name": "resolved" } ], "name": "status", "label": "Status", "dataType": "STATUS" }, { "name": "priority", "label": "Priority", "dataType": "STRING" }, { "name": "project", "label": "Project", "dataType": "STRING" } ], "associatedHubSpotObjectTypes": [ "COMPANY" ], "associatedHubSpotObjectTypeProperties": { "COMPANY": [ "domain" ] } }
The following shows how the different record type properties show up to the user:
See the specific docs for managing record types through the API:
You can also create and manage record types from your developer account. In your app settings, you can create record type(s) from the CRM cards tab.
Once you create a new CRM card, you can also manage its settings by clicking on the name of the card.
Note: You can create up to 25 record types/CRM cards
HubSpot makes a data fetch request to the integration when a HubSpot user views a CRM record. This request happens each time a user visits the specified associatedHubSpotObjectTypes for the CRM extension type, currently one or more of contacts, companies, deal, or tickets.
HubSpot will make a separate request for each record type. HubSpot will send the request to the dataFetchUri
specified on the record type.
The response to this data fetch request should contain information to display to the user at that time. It can contain up to five card properties. If more card properties are available for this specific CRM object, the integrator can link to them.
GET https://example.com/demo-tickets?userId=12345&userEmail=testuser@example.com&associatedObjectId=78912&associatedObjectType=COMPANY&portalId=9999999&domain=testcompany.com
With a header:
X-HubSpot-Signature: <some base64 string>
The query parameters provided in this request are:
userId
: The numeric userId of the customer requesting data.userEmail
: The user address, in HubSpot, of the user requesting data.associatedObjectId
: The ID for the current object, depending on the associatedObjectType
. This will be the companyId
, dealId
, contact vid
, or objectId
for tickets.associatedObjectType
: The type of object the user is requesting data about (CONTACT
, COMPANY
, DEAL
, or TICKET
). This will be one of the associatedHubSpotObjectTypes
provided for this record type.associatedHubSpotObjectTypeProperties
. If one of the request properties is not defined for the current object, it will not be listed in the query string. In the example above, the company property domain
is included. Request properties can be defined in the record type interface, per the screenshot below:
The X-HubSpot-Signature
header provides a way for the integrator to verify this request came from HubSpot. See Request Signatures for details.
This is an example response the integrator should provide to the above request.
{ "results": [ { "objectId": 245, "title": "API-22: APIs working too fast", "link": "http://example.com/1", "created": "2016-09-15", "priority": "HIGH", "project": "API", "reported_by": "msmith@hubspot.com", "description": "Customer reported that the APIs are just running too fast. This is causing a problem in that they're so happy.", "reporter_type": "Account Manager", "status": "In Progress", "ticket_type": "Bug", "updated": "2016-09-28", "actions": [ { "type": "IFRAME", "width": 890, "height": 748, "uri": "https://example.com/edit-iframe-contents", "label": "Edit", "associatedObjectProperties": [] }, { "type": "IFRAME", "width": 890, "height": 748, "uri": "https://example.com/reassign-iframe-contents", "label": "Reassign", "associatedObjectProperties": [] }, { "type": "ACTION_HOOK", "httpMethod": "PUT", "associatedObjectProperties": [], "uri": "https://example.com/tickets/245/resolve", "label": "Resolve" }, { "type": "CONFIRMATION_ACTION_HOOK", "confirmationMessage": "Are you sure you want to delete this ticket?", "confirmButtonText": "Yes", "cancelButtonText": "No", "httpMethod": "DELETE", "associatedObjectProperties": [ "protected_account" ], "uri": "https://example.com/tickets/245", "label": "Delete" } ] }, { "objectId": 988, "title": "API-54: Question about bulk APIs", "link": "http://example.com/2", "created": "2016-08-04", "priority": "HIGH", "project": "API", "reported_by": "ksmith@hubspot.com", "description": "Customer is not able to find documentation about our bulk Contacts APIs.", "reporter_type": "Support Rep", "status": "Resolved", "ticket_type": "Bug", "updated": "2016-09-23", "properties": [ { "label": "Resolved by", "dataType": "EMAIL", "value": "ijones@hubspot.com" }, { "label": "Resolution type", "dataType": "STRING", "value": "Referred to documentation" }, { "label": "Resolution impact", "dataType": "CURRENCY", "value": "94.34", "currencyCode": "GBP" } ], "actions": [ { "type": "IFRAME", "width": 890, "height": 748, "uri": "https://example.com/edit-iframe-contents", "label": "Edit" }, { "type": "CONFIRMATION_ACTION_HOOK", "confirmationMessage": "Are you sure you want to delete this ticket?", "confirmButtonText": "Yes", "cancelButtonText": "No", "httpMethod": "DELETE", "associatedObjectProperties": [ "protected_account" ], "uri": "https://example.com/tickets/245", "label": "Delete" } ] } ], "settingsAction": { "type": "IFRAME", "width": 890, "height": 748, "uri": "https://example.com/settings-iframe-contents", "label": "Settings" }, "primaryAction": { "type": "IFRAME", "width": 890, "height": 748, "uri": "https://example.com/create-iframe-contents", "label": "Create Ticket" } }
Definitions for the fields in the response body:
results
: A list of up to five valid card properties. See the card properties section for details.totalCount
: The total number of card properties available, if there are more than five related to the requested CRM object. This property is optional.allItemsLink
: A URI that shows all card properties associated with the requested CRM object, if there are more than five. This property is optional.itemLabel
: The label to be used in the "see more" link. (e.g. "See more tickets") If not provided, this falls-back to the record type's Title
. This property is optional.settingsAction
: An iFrame Action that gives users the ability to update settings for this integration. See Action Types for details on specifying Actions. This property is optional.primaryAction
: The primary action for a record type. This is typically a "creation" action. See Action Types for details on specifying Actions. This property is optional.secondaryActions
: A list of actions to display on the card level. See Action Types for details on specifying Actions. This property is optional.JSON for an example card property that is returned in the example response above:
{ "objectId": 988, "title": "API-54: Question about bulk APIs", "link": "http://example.com/2", "created": "2016-08-04", "priority": "HIGH", "project": "API", "reported_by": "ksmith@hubspot.com", "description": "Customer is not able to find documentation about our bulk Contacts APIs.", "reporter_type": "Support Rep", "status": "Resolved", "ticket_type": "Bug", "updated": "2016-09-23", "properties": [ { "label": "Resolved by", "dataType": "EMAIL", "value": "ijones@hubspot.com" }, { "label": "Resolution type", "dataType": "STRING", "value": "Referred to documentation" }, { "label": "Resolution impact", "dataType": "CURRENCY", "value": "94.34", "currencyCode": "GBP" } ], "actions": [ { "type": "IFRAME", "width": 890, "height": 748, "uri": "https://tools.hubteam.com/integrations-iframe-test-app", "label": "Edit" }, { "type": "CONFIRMATION_ACTION_HOOK", "confirmationMessage": "Are you sure you want to delete this ticket?", "confirmButtonText": "Yes", "cancelButtonText": "No", "httpMethod": "DELETE", "associatedObjectProperties": [ "protected_account" ], "uri": "https://api.hubapi.com/linked-sales-objects-test-application/v1/actions/demo-ticket/988", "label": "Delete" } ] }
Properties:
objectId
: A unique ID for this object. This property is required.title
: The title of this object. This property is required.link
: The URI the user can follow to get more details about this object. This property is optional, but if not all objects have a link you should provide a value of null
.properties
: A list of custom properties that are not defined in the record type. You can use this list to display properties unique to this specific object. These properties will be shown after the properties defined in the object-type in the order they're provided. This property is optional.actions
: A list of actions that are available to take on this object. See Action Types for details on specifying Actions. This property is optional.
In addition to the above properties, the integrator can provide values for the properties defined on the object-type. In the above example the created
JSON property:
"created":"2016-08-04"
Is providing a value for this object for the created
property defined on the record type.
When a user clicks on an action that is defined as an action hook, HubSpot will send a request using the URI and HTTP method specified in the action definition.
Example Request
DELETE https://example.com/tickets/245?userId=12345&userEmail=testuser@example.com&associatedObjectId=78912&associatedObjectType=COMPANY&portalId=9999999&domain=testcompany.com
With a header:
X-HubSpot-Signature: <some base64 string>
The query parameters provided in this request are:
userId
: The numeric userId of the customer requesting data.userEmail
: The user address, in HubSpot, of the user requesting data.associatedObjectId
: The ID for the current object, depending on the associatedObjectType
. This will be the companyId
, dealId
, contact vid
, or objectId
for tickets..associatedObjectType
: The type of object the user is requesting data about (CONTACT
, COMPANY
, DEAL
, or TICKET
).portalId
: The portal ID (also called Hub ID) of the customer that is requesting data. This will be a customer that has installed your integration.associatedObjectProperties
. If one of the request properties is not defined for the current object, it will not be listed in the query string. In the above example, the company property domain
is included.The X-HubSpot-Signature
header provides a way for the integrator to verify this request came from HubSpot. See Request Signatures for details.
Example Response
{ "message": "Successfully deleted object" }
HubSpot will attempt to parse responses to action hooks as JSON and look for a message
property. HubSpot will display this message
to the user on either success or failure.
Response status code of 2xx
will show a success message and status codes of 4xx
or 5xx
will show an error message.
The following sections provide details about each type of action that can be specified.
When a user clicks an iframe action, a modal dialog will open containing an iframe pointing at the provided URL. No request signature is sent when the iframe is opened from the CRM UI. This is because the iframe URL is returned in the original data fetch request, and no additional proxy requests are needed.
Example iframe action:
{ "type": "IFRAME", "width": 890, "height": 748, "uri": "https://example.com/iframe-contents", "label": "Edit", "associatedObjectProperties": [ "some_crm_property" ] }
type
: Should be IFRAME
to indicate that this is an IFrame action.width
, height
: The dimensions that the iframe should be.uri
: The URI to open inside the iframe.label
: The label to display in the action dropdown.associatedObjectProperties
: A list of properties on the associated contact, company, deal, or ticket. The values of the properties for the current object will be appended to the uri
as query parameters when opening the iframe.When the user is done completing an action inside the iframe the modal dialog should close, returning the user back to the CRM screen they started from. To close the dialog model, the integrator can use window.postMessage
to signal to the CRM that the user is done. The following messages are accepted.
{"action": "DONE"}
- The user has successfully completed the action.{"action": "CANCEL"}
- The user has canceled the action.Example: window.parent.postMessage(JSON.stringify({"action": "DONE"}), "*");
Note: Iframe modals accessed through an iFrame action will have a responsive width.
Action hook actions send a server-side request to the integrator. The only UI a users sees for this action is a success or error message. This type of action is useful for simple operations that require no further input from the user. An X-HubSpot-Signature
header will be included in the request. Learn more about request signatures.
Example action hook action definition:
{ "type": "ACTION_HOOK", "httpMethod": "POST", "uri": "https://example.com/action-hook", "label": "Example action", "associatedObjectProperties": [ "some_crm_property" ] }
type
: Should be ACTION_HOOK
to indicate that this is an action hook action.httpMethod
: The HTTP method to use when making the request. This can be GET
, POST
, PUT
, DELETE
, or PATCH
.uri
: The URI of the request to make.label
: The label to display in the action drop-down.associatedObjectProperties
: A list of properties on the associated contact, company, deal, or ticket. If httpMethod
is GET
or DELETE
than these property values will be appended to the URI of the request as query parameters. Otherwise they will be sent as a request body parameters.See Handling Action Hooks for more details on how to implement the action endpoint.
Confirmation actions behave the same as action hooks except that a confirmation dialog is shown to the user before running the server-side request. An X-HubSpot-Signature
header will be included in the request. Learn more about request signatures.
{ "type": "CONFIRMATION_ACTION_HOOK", "httpMethod": "POST", "uri": "https://example.com/action-hook", "label": "Example action", "associatedObjectProperties": [ "some_crm_property" ], "confirmationMessage": "Are you sure you want to run example action?", "confirmButtonText": "Yes", "cancelButtonText": "No" }
type
: Should be CONFIRMATION_ACTION_HOOK
to indicate that this is a confirmation action hook action.httpMethod
: The HTTP method to use when making the request. This can be GET
, POST
, PUT
, DELETE
, or PATCH
.uri
: The URI of the request to make.label
: The label to display in the action drop-down.associatedObjectProperties
: A list of properties on the associated contact, company, deal, or ticket. If httpMethod
is GET
or DELETE
than these property values will be appended to the URI of the request as query parameters. Otherwise they will be sent as a request body parameters.confirmationMessage
: The message to display to the user in the confirmation dialog.confirmButtonText
: The text for the "OK" button. This is optional, the button text will default to "OK".cancelButtonText
: Text text for the "Cancel" button. This is optional, the button text will default to "Cancel".See Handling Action Hooks for more details on how to implement the action endpoint.
Note: Requests made for CRM 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.
To ensure that the requests you're getting at your data fetch URIs and action hook URIs are actually coming from HubSpot, we populate a request header named X-HubSpot-Signature
. This header will contain a hash of the of the app secret for your application and the details of the request.
To verify this signature, perform the following steps:
App secret + http method + URI + request body (if present)
Note: for iframe requests, an X-HubSpot-Signature
header will not be included. To verify the request, you’ll need to set up another method of verification. For example, you could add your own request token to the iFrame URL. Learn more in the HubSpot Community.