As a platform, HubSpot has a massive amount of UI-based functionality. But as any developer will tell you, no platform is truly complete without some kind of API. This allows users to have an even greater amount of control over their instances, and is essential to any top tier platform.
HubSpot’s REST API has gone through a few versions and is currently in a rock-solid iteration that is among the best that I have worked with. It gives you backend access to all of HubSpot’s default objects, in addition to custom objects, and is flexible enough to allow for myriad applications.
The API is currently in the midst of a change that is sunsetting API keys for accounts, and instead giving access to individual applications in order to bring greater flexibility in coding API-based projects, and give added security and accountability to the same.
Most platforms would consider this to be enough to make developers and clients happy, and rightfully so— but HubSpot has gone a step further.
HubSpot has been building their own Python library for some time now, and we’ve been keeping an eye on it. It has now reached the stage where they’ve put it front and center in their API documentation, so we thought this would be the perfect time to dive into it and bring back some code examples and impressions.
This blog post will specifically evaluate the CRM base object capabilities in the library, although we plan to expand on this in future posts!
Contacts
We’ll kick things off with the Contact object in HubSpot. Unsurprisingly, this is a key aspect of any CRM, and carries a lot of importance with it. Almost all of the HubSpot development that I’ve personally done has involved contacts in one way or another. Because it’s such an important aspect of the CRM, it is often referenced when writing custom apps for HubSpot.
There are a myriad of uses for contact-based API calls, so listing them all out is basically an impossible task. However, some very common ones include creating and updating contacts, searching through using unique field values and IDs, and archiving/deleting contacts. Moving on from this, a common one with larger projects is batch actions which allow for doing such tasks en masse.
Their library allows for these actions using basic function calls within your script, which can start with something as simple as a single contact creation with an array of field values, and expand beyond that with some basic coding. I wrote a simple example to get you started in which the library is called in a loop to create contacts using fields in a CSV.
import hubspot
from pprint import pprint
import pandas as pd
from hubspot.crm.contacts import SimplePublicObjectInput, ApiException
import os
# setting up the connection to HubSpot
token = os.environ["private_key"]
client = hubspot.Client.create(access_token= token)
# reading in the csv using Pandas
df = pd.read_csv("Contact CSV.csv", header=0)
# looping through the dataframe
for index, row in df.iterrows():
properties = {
"company": row["Company"],
"email": row["Email"],
"firstname": row["First Name"],
"lastname": row["Last Name"]
}
simple_public_object_input = SimplePublicObjectInput(properties=properties)
# attempting to create the contact, printing the error exception if unsuccessful
try:
api_response = client.crm.contacts.basic_api.create(simple_public_object_input=simple_public_object_input)
pprint(api_response)
except ApiException as e:
print(f"Exception when calling basic_api->create: {e}\n")
As you can see above we’re using Pandas to load a CSV with mapped HubSpot fields into a dataframe. We are then looping through that dataframe and creating a contact with each row’s information.
Deals
The Deals object in HubSpot also sees a fair amount of traffic. Thanks to their built-in associations with the Company and Contact objects and native availability, they can be used in a number of ways outside of their original intended purpose of, well, tracking deals.
I’ve seen them used to take the place of a ticketing system, track donations, and even, through a specifically automated naming convention and duplicating workflow, be used to simulate a parent-child relationship that doesn’t currently exist for deals in HubSpot.
Due to this versatility, the Deals object can often show up in API calls in custom scripts. Luckily, the library has that pretty well covered. As an example, I wrote a simple script that searches for deals in the HubSpot instance, using a CSV of IDs, and returning a series of fields on the deal.
import hubspot
from pprint import pprint
import pandas as pd
from hubspot.crm.deals import PublicObjectSearchRequest, ApiException
import os
# setting up the connection to HubSpot
token = os.environ["private_key"]
client = hubspot.Client.create(access_token= token)
# reading in the csv using Pandas
df = pd.read_csv("Deal CSV.csv", header=0)
# looping through the dataframe
for index, row in df.iterrows():
# attempting to get the deal, printing the error exception if unsuccessful
try:
api_response = client.crm.deals.basic_api.get_by_id(deal_id=row["ID"], properties=["amount", "dealname", "dealstage", "pipeline", "createdate", "closedate"], archived=False)
pprint(api_response)
except ApiException as e:
print(f"Exception when calling basic_api->get_by_id: {e}\n")
Here we’re again using Pandas to load a CSV containing HubSpot deal IDs into a dataframe. We are then looping through that dataframe and searching for the matching deal, and displaying the desired properties.
Companies
The final member of the main three objects is Companies. Much like Deals and Contacts before it, Companies is an extremely commonly used object in HubSpot. It allows for a number of different associations, up to and including the coveted Parent-Child relationship. The most common of these is of course contacts who work at the company, and that was the focus of the code snippet I wrote for this demo.
Getting a list of associated items is a fairly common ask in the work that I do as a HubSpot developer, so I thought a good demo would be a small script loops through a CSV of companies, and then pulls the first ten contacts associated with each company.
import hubspot
from pprint import pprint
import pandas as pd
from hubspot.crm.companies import ApiException
import os
# setting up the connection to HubSpot
token = os.environ["private_key"]
client = hubspot.Client.create(access_token= token)
# reading in the csv using Pandas
df = pd.read_csv("Company CSV.csv", header=0)
# looping through the dataframe
for index, row in df.iterrows():
# attempting to get the associations, printing the error exception if unsuccessful
try:
api_response = client.crm.companies.associations_api.get_all(company_id=row["ID"], to_object_type="contact", limit=10)
pprint(api_response)
except ApiException as e:
print(f"Exception when calling associations_api->get_all: {e}\n")
As before, we’re using Pandas to load a CSV containing a series of company IDs into a dataframe. We then loop through said dataframe, and pull the first ten contacts associated with the company.
Pointed Pros vs. Cons
Having now done some work with this library, I figured a more pointed Pros vs. Cons list would be a good idea to give a bit of a TLDR for those who want one.
Pros:
- Standard Pip install
- There isn’t any additional headache when setting up this library in your IDE. You just throw in the pip command, and away you go.
- Easy to pick up and use
- It’s a simple matter of calling the library in your code, and then going to town. They have a large amount of code examples in their API documentation, and a fully supported Github repository for further delving if you’re interested.
- API Exception is a handy tool
- The library has something of a built in logging/debugging tool in the form of the API Exception call that’s sitting on the end of each of the above scripts.
Cons:
- Requires installation of the library
- If you’re concerned about taking up unnecessary space on a server hosting your code, then installing an extra library could be a concern.
- Requires Python 3.5+
- If you prefer to use older builds of Python, then using this library isn’t going to be an option.
- Less flexibility than straight up Requests
- Using this library allows for less overall usability and flexibility than using the classic Requests
- Engagements are no-go
- If you want to get engagements on a record, i.e. calls on a contact record, you’ll still need to use Requests and their legacy API.
Closing Thoughts
Whew! Well, that was a bit of a journey, but I think we landed in a pretty good place.
I’ll say that my impressions of the HubSpot library so far have been almost entirely positive. There are a good number of important pros to using it, and a limited number of cons. I think there’s still a good bit more to unpack here, but I’m excited at the prospect of continuing to dig into the depths of HubSpot’s library on your behalf.
Keep a look out for the next post where we’ll take a look at custom objects, batch jobs, and more. Don’t worry though, on the advice of Gandalf I’ll be sure to delve neither too deep, nor too greedily.