Summary
You can use HubSpot workflows to reflect HubSpot "labels" in Planhat
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:
HubSpot workflows to enable mapping of value labels - "Deal Stage" example
As stated in the main article on setting up the HubSpot integration, the default behaviour is that Planhat integrates with the internal values of HubSpot fields, rather than the labels. This means, for example, that if you mapped the HubSpot "Deal Stage" field (on the Deal object) to Planhat, the field value "Closed Won" would actually be sent to Planhat as "closedwon", since that's the internal value.
In most cases, this is fine, because the internal values generally correspond fairly well with the labels you set. When you add a new "Deal Stage" value, you will notice that HubSpot auto-fills the internal value to match the label, but in lower case. However, some default internal values are numeric, which are not very intuitive when integrating data. There is a solution available to you, though!
If you want to work with the labels of, for example, HubSpot "Deal Stage", then we recommend an approach using HubSpot workflows, as detailed below.
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 have control over the internal 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
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 labels of your HubSpot "Deal Stage" field - e.g. "Closed Won", "Qualified", "Lead" 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 labels of the "Deal Stage" in HubSpot. For example, if the HubSpot "Deal Stage" field has a value with the label "Closed Won", then the "PH Deal Stage" field should have a value with the label and internal value "Closed Won", and the "Sales Stage" field in Planhat should also have the value of "Closed Won" (as described above)
You then create two workflows in HubSpot - you can look at the example image below as 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 of 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