Summary
By default, you reference HubSpot "choosing option" fields by label, not internal value. You can use HubSpot workflows if you want to reflect HubSpot internal values in Planhat for specific fields (useful if you have duplicate labels in HubSpot due to multiple pipelines)
The integration has a "virtual field" to facilitate syncing Company domains
You can map a non-Company HubSpot object (e.g. Deal) to the Planhat Company model
The integration sends and fetches data sequentially, at a high frequency. This means the integration is generally working in "real time", in response to record creation/update
Who is this article for?
All Planhat users
It's particularly relevant to those setting up the HubSpot v2 integration
Series
This article is part of a series on the HubSpot v2 integration:
HubSpot v2 integration: technical deep dive β¬ οΈ You are here
Article contents
Introduction
π Important to note
This article relates to version 2 (v2) of Planhat's HubSpot integration - the current version.
For information on v1, the legacy version of the HubSpot integration, see here.
This is a technical deep-dive article
Read on if you'd like to explore some specific details of the HubSpot v2 integration.
If you'd like an introduction to the HubSpot v2 integration, please refer to our main article for an overview of the key points.
The HubSpot integration is easy to use, prepopulating configuration that you can leave on the default settings if they suit you. However, it's also incredibly flexible, allowing you to modify the configuration to suit your specific needs.
In this article, we take you through some of the ways you can tailor the integration. We also provide more detailed information on some specific setups and aspects of the integration than is covered in the main overview article.
Data mapping - special cases
In this section:
Syncing with HubSpot "choosing option" fields
HubSpot, like Planhat, has a number of field types that support "choosing options":
Single checkbox
Multiple checkboxes
Dropdown select
Radio select
System pipeline fields, e.g. on the Company or Ticket objects
When syncing your Planhat data with these fields, you should make sure that there is a perfect match (case sensitive) between the options available in Planhat, and the labels (not internal values) for the options in HubSpot.
π Important to note
Matching of Planhat values with HubSpot label (UI) values is now the default for the integration - and this is what we'll discuss/assume in the rest of this article.
However, the original behaviour was to match with HubSpot internal (API) values, and some Planhat tenants may be set to maintain this behaviour. If your tenant is matching with internal values and you would like to switch to using labels, please reach out to your CSM or TAM, or our Support team.
For some customers, it may actually be preferable to sync with HubSpot's internal values rather than labels - if your tenant is set to use labels and you want to switch, we can help you with that too!
How does matching on labels work?
In short, when the integration performs the "translation" of converting between HubSpot label (UI) values and internal (API) values for you.
We store a table that matches the labels and internal values of the above-mentioned HubSpot fields. Then, when fetching from HubSpot, you should filter on label, and we will take the values you have referenced (e.g. "Onboarding") and replace those labels with the appropriate stored internal (API) values when we query HubSpot.
We do the same when sending data to HubSpot - in the payload we send to HubSpot's API, we take each field label value (e.g. "Onboarding") and replace it with whatever the correct internal value is.
An example
If you want to:
Sync the Planhat "Phase" field with the HubSpot "Lifecycle Stage" field
Filter Companies to fetch from HubSpot based on "Lifecycle Stage" being any of Onboarding, Adoption, or Expansion
... then you would need to ensure that the available options for the Planhat Phase field are the same as the labels (not internal values) for the available options in HubSpot's Lifecycle Stage field, and you would set up the fetching filter as shown below:
HubSpot workflows to enable mapping of internal values - "Deal Stage" example
Introduction
As we mentioned above, the default behaviour for the current HubSpot integration is that Planhat field values are mapped with HubSpot label (UI) values, rather than internal (API) values. In the vast majority of cases, this is much more convenient for you than needing to use HubSpot internal values as your values in Planhat (which can lack formatting, or even simply be a numerical value), or set up workflows in HubSpot (see below) to convert every HubSpot field.
However, it's important to note that for the mapping via labels to work properly, the HubSpot label values must be unique - you can't have duplicates. For example, if you wanted to map (sync) the HubSpot "Deal Stage" field (on the Deal object) bidirectionally, but you had multiple HubSpot pipelines each with a "Closed Won" label value, this would cause issues, because the integration wouldn't be able to differentiate between the duplicates and identify the respective internal values.
Therefore, if you want to sync HubSpot "Deal Stage", and are using multiple pipelines in HubSpot, with duplicate labels (e.g. multiple "Closed Won" across the pipelines), then you should use workflows (automations) in HubSpot to populate a custom field with the unique internal values, which you can sync with Planhat instead. This workaround enables you to keep the integration in your Planhat tenant set to match on HubSpot labels, which is best for most other fields. (This approach assumes that you can't change your labels in HubSpot to be unique, and that you don't want to switch the whole integration to sync with HubSpot's internal values instead of labels.)
Technical setup
This scenario assumes you're syncing the Planhat Opportunity model to the HubSpot Deal object, bidirectionally. If you are only syncing in one direction, you are unlikely to need both the workflows in the instructions below.
The basic principle is:
You create a custom field in HubSpot ("PH Deal Stage" in the example below, but you could potentially call this something else if you wanted)
This is to act as a mirror of the default HubSpot field "Deal Stage", except in this custom field you can surface the internal values to be the label values
The HubSpot workflows transfer data between these two HubSpot fields
You then use the custom field in your field mapping in the HubSpot integration (to the "Sales Stage" field on the Planhat Opportunity model), instead of mapping the default HubSpot "Deal Stage" field
In short, this process moves the Deal Stages, which you want to sync, into a new custom field in HubSpot, where the label values are unique and can sync without issue.
More detailed method:
You will use 1 field in Planhat: "Sales Stage" (system field) on the Opportunity model
Customise this list field so the available options/values match the internal values of your HubSpot "Deal Stage" field - e.g. "closedwon" etc.
You will use 2 fields in HubSpot:
"Deal Stage": this field has labels and internal values, e.g. "Closed Won" (label), and "closedwon" (internal value)
"PH Deal Stage": this is a custom field you create. This field should have labels and internal values matching both the "Sales Stage" field in Planhat and the internal values of the "Deal Stage" field in HubSpot. For example, if the HubSpot "Deal Stage" field has an option with the internal value "closedwon", then the "PH Deal Stage" field should have an option with the label and internal value both as "closedwon", and the "Sales Stage" field in Planhat should also have the value of "closedwon" (as described above)
You then create two workflows in HubSpot - you can look at the example image below for guidance
Workflow 1: "Set Deal Stage when PH Deal Stage is updated"
The trigger is that "PH Deal Stage" is updated
Branch 1: goes to the correct pipeline
Branch 2: checks the value set for "PH Deal Stage"
Each branch below (see diagram): checks if the value set for "Deal Stage" corresponds to the value set for "PH Deal Stage"
If "stage is the same", then the automation does nothing (which prevents looping). If not, the "Deal Stage" is given the value that corresponds with "PH Deal Stage"
Workflow 2: "Set PH Deal Stage when Deal Stage is updated"
Make this the same as workflow 1, but with the inverse logic
The diagram below shows an example similar to workflow 2: "Set PH Deal Stage when Deal Stage is updated". In this example, the workflow is scheduled daily, but you could easily make the workflow trigger whenever the "Deal Stage" is updated, as described above.
Click the image to view it enlarged
Mapping Company domains
In HubSpot, the Company domain is stored in two different fields:
"Company Domain Name", which contains 1 primary domain
"Additional Domains", which contains an array of additional domains associated with the Company
In Planhat, all the domains associated with a Company are stored in a single array field: "Related Domains"
Since mapping both of the HubSpot fields with the Planhat "Related Domains" field would cause data duplication in HubSpot, we have created a "virtual field" for the purpose of integrating domain data between Planhat and HubSpot. The virtual field is called "Company Domains (virtual field)" and is accessible in the field mapping dropdown as if it were a HubSpot field.
When you map Planhat "Related Domains" to HubSpot "Company Domains (virtual field)":
Fetching from HubSpot: we fetch both HubSpot "Company Domain Name" and HubSpot "Additional Domains", merge the contents into one array - the "Company Domains (virtual field)" - and send this array to Planhat "Related Domains"
The reverse happens when sending to HubSpot: the first domain in the Planhat "Related Domains" array is sent to HubSpot "Company Domain Name", and the remaining domains in the array are sent to HubSpot "Additional Domains"
Mapping Owners and Users
In HubSpot, you can assign a single Owner to records. This data can be bidirectionally synced with Planhat, with the integration using some clever configuration we've built in for you.
In HubSpot, the Owner/User field stores an ID that is specific to HubSpot, whereas the corresponding field in Planhat stores an ID that is specific to Planhat.
In order to enable sync of this data, we continuously fetch a list of all HubSpot Users (their IDs and email addresses), and add the Planhat IDs of Users that match these email addresses to the list. This list can't be seen anywhere - it is solely used by the integration to match HubSpot IDs (and therefore Users) with Planhat IDs (and so Users), using email address as the common denominator.
When you select a HubSpot default Owner field or a HubSpot custom User field in the integration, and map it to a Planhat Team Member field, we "replace" values with the "ExternalOwnerId" that we get from HubSpot. If, instead, you map default HubSpot fields such as "created by" and "updated by", you will find that we "replace" values with "ExternalUserId", a different HubSpot ID type.
You can view this by clicking on the chevron on the right-hand side of the field mapping row to expand it out. You'll see "Replace with value when receiving from / sending to HubSpot" dropdown menus, as shown below.
We populate this data for you, and in most cases you don't need to change it. The reason the "replacements" are editable is to enable you to change the setup in case of any edge cases.
Field mapping - field type compatibility
The diagram below illustrates the compatibility between different Planhat and HubSpot field types. Use this to help guide your field mapping.
Click the image to view it enlarged
"Syncs with some caveats" means that you can sync data in at least one direction, but that perfect compatibility may not be available, or is not intended. For example:
If a Planhat list field has a value "true", then this may be compatible with a HubSpot checkbox field, but Planhat has a checkbox field type that we recommend using to sync with HubSpot checkboxes
If syncing from a Planhat rich text field to a HubSpot single-line text field, note that rich text supports formatting such as bold, while a HubSpot single-line text field does not support formatting
Mapping Planhat Company model to any HubSpot object (e.g. Deal)
As we discuss in the main HubSpot integration article, in the Planhat data hierarchy the Company model is at the top. All other Planhat models that can be mapped/synced in the integration must link to the Company model. For example, a License or an End User cannot exist without a connection to a Company. The Company Profile is also a central place where various data types are compiled.
In the majority of cases, the HubSpot integration is configured with the Planhat Company model mapped to the HubSpot Company object. This is the default that is prepopulated when you first authenticate the integration. However, you can change this so that a different HubSpot object (such as Deal) is linked to the Planhat Company model instead.
The integration has been built with this flexibility so that it can accommodate setups in HubSpot where you don't use the Company object - typically, this is where you use the Deal object as your focal point in HubSpot instead. If you can't (or don't want to) restructure your HubSpot data to have Companies attached to your Deals (one Company per Deal), and you want HubSpot Deals to become Planhat Companies instead, you can configure the integration to enable this.
This is easy to do. Once you have chosen the HubSpot object that's mapped to the Planhat Company model, you just have to make sure that in the other sync sections (for other model/object pairs) the "Associated model" on the HubSpot side is set to this HubSpot object instead of the (default) Company HubSpot object.
This is shown below, taking the example of mapping the HubSpot Deal object to the Planhat Company model. The "Associated model in HubSpot", shown on the right for the End User / Contact sync, also needs to be set to this object in all the other sync sections you map.
Sync frequency, rate limits, and the cascade structure
Planhat's HubSpot integration supports regular sync of very large volumes of data. It is also very fast, syncing new and updated records in near real-time.
For optimal performance, the integration balances speed with rate limits - it is dynamic to ensure we always sync as much data as possible, as quickly as possible, given a number of constraints:
HubSpot rate limits (number of API requests per time period)
HubSpot limits on number of records included per request
Planhat limits on data processed over a given timespan (not fixed - dynamic)
π Definition
A "record" is the data within the HubSpot object or Planhat model - e.g. for the Company object/model, individual records could be "Apple", "Microsoft" and "Google"
Rate limits
The HubSpot integration applies the following rate limits:
Sending to HubSpot
Create 600 records per minute in HubSpot (600 API requests per minute; 1 record per request)
Every time we create a record in HubSpot, we send a single request to HubSpot. This is because we need to take the record ID from HubSpot's API response, and store it as the Source ID (or External ID in some cases)
Update 60,000 records per minute in HubSpot (600 API requests per minute; 100 records per request)
Fetching from HubSpot (i.e. syncing from HubSpot to Planhat)
Create 24,000 records per minute in Planhat (240 API requests to fetch records, and 240 API requests to fetch their associations, per minute; 100 records per request)
Update 24,000 records per minute in Planhat (240 API requests to fetch records, and 240 API requests to fetch their associations, per minute; 100 records per request)
"Associations" in this context means references on those records to record of other objects
It is important to note that HubSpot's rate limits are not the only consideration affecting how fast/often data is actually ingested on either side. Both Planhat and HubSpot (depending on the sync direction) may also need a short time to process the data, so exact timings are not guaranteed.
How does the sync work?
The integration continually sends relevant data to HubSpot (if that sync is enabled), and fetches data from HubSpot, provided that 1) the records are associated with a Company that exists in Planhat, and 2) the records have been updated since the section last synced.
This is a summary of how the sync works. It's describing the scenario of a bidirectional sync.
Every 10 seconds (this may change in future), the integration queries what updates have been made in Planhat (only relevant records, considering your integration configuration), since the last time we synced
A "sync job" is initiated:
It begins by looking at the Planhat Company model
It sends Planhat Companies (creations/updates) to the HubSpot object that's mapped to Planhat Companies (typically the HubSpot Company object)
It fetches HubSpot records to be synced back to the Planhat Company model
The integration queries which HubSpot records mapped to the Planhat Company (typically HubSpot Company records) have been created/updated in HubSpot since the last sync (respecting your configuration in the integration, including filtering)
We fetch these records, and sync them into Planhat via the Planhat API
Then the integration moves onto the next Planhat model
As you just saw with Companies, firstly we send the relevant data to HubSpot (e.g. sending new/updated Planhat End Users to the HubSpot Contact object) ...
... and then we fetch the relevant records from HubSpot (e.g. created/updated Contacts) and their associations, and sync them into Planhat
Then the integration moves onto the next Planhat model in the list, and so on, until all of the sync sections you have set up in the integration have been processed. That's completion of the first "sync job", which means the next one can start
You may hear this referred to as "the cascade structure".
Remember, the rate limits are the limiting factor if the data can be quickly processed in Planhat or HubSpot (depending on direction). This will generally be the case, but it is not guaranteed. The "sync job" that sends and fetches data waits for the previous job to complete before starting a new job, so there may be times when the frequencies/volumes are lower than the rate limits.
π Important to note
If a Company is fetched from HubSpot and created in Planhat, any other records related to that Company will also be fetched, even if they haven't been updated in HubSpot, respecting whatever filter rules are set in each sync section in the integration. For example, if you have 3 sync sections - 1 to fetch HubSpot Companies, 1 to fetch Contacts, and a final one to fetch Deals, and a Company is fetched and created from HubSpot, then Planhat fetches all related Contacts and Deals (respecting the integration filtering, of course).
Further reading
If you would like to remind yourself of the main elements of the HubSpot integration, and see how to set it up, check out this article
If you have any remaining questions about the integration, or need additional help, you can refer to our troubleshooting and FAQ article