Step by Step Guide to building a native HubSpot API integration

How to build a native HubSpot API integration for your SaaS product

Robin Guldener
April 30, 2024
19
min read

The good news: HubSpot’s API is one of the most dev friendly

Thankfully, HubSpot is one of the most developer-friendly api integrations you can build, with plentiful documentation and robust developer accounts.

Nevertheless, it still comes with its own set of quirks, nuances, and pitfalls and it is no small task to spin up and maintain a customer-facing HubSpot API integration.

Fortunately, we’ve already gone through the headache of building and maintaining complex HubSpot api integrations and have distilled all of the wisdom and gotchas we’ve picked up over the years into this guide.

Getting Setup For your HubSpot API Integrations

Before you dive into writing code for your HubSpot integrations, there are a few logistical things to get out of the way.

Once these are done you can start writing your own HubSpot API integration!

Create a HubSpot Developer Account

First, you’ll need access to a developer account for your HubSpot integrations. This lets you muck around with fake HubSpot data without worrying about messing up anything in a real user's account.

Developer accounts are free and have essentially the same functionality and HubSpot data as a real account. This makes them great to develop your HubSpot integrations.

⇒ Get your developer account here: https://developers.hubspot.com/get-started

Create A HubSpot OAuth App

HubSpot recently sunset support for HubSpot API key access, so you must create an OAuth app to access your customer’s HubSpot account data. We will show you later on how to use this app to connect to your customer's account.

To create an app, you can log into your developer account, head to the ‘Apps’ navigation section, and click ‘Create app’.

This should spin up a new draft OAuth app. You can ignore most of the configuration for now.

There are only two things you need to fill in:

  1. The Scopes: For this tutorial we will give ourselves CRM contact read and write access but you can pick whatever objects you’d like. You can edit them later on, so don’t worry about nailing the exact set you need rThe OAuth redirect URL: In addition, you need to fill in the redirect URL. If you want to use Nango’s free OAuth feature you can put https://api.nango.dev/oauth/callback here
  1. The OAuth redirect URL: In addition, you need to fill in the redirect URL. If you want to use Nango’s free OAuth feature you can put https://api.nango.dev/oauth/callback here

That’s it. Now you have a working OAuth app and are ready to get building 👷🏻‍♂️!

Head to the next section for a breakdown of how to build your HubSpot api integration.

The HubSpot API at a Glance

Here’s a quick summary of some important things to know about the HubSpot platform & API.

Adding Authentication to your HubSpot API integration

Before we can make an API request, we need to get the user’s permission to access their HubSpot data.

We do this by “installing” the OAuth app we created in the step above in their HubSpot CRM instance.

During this process, your user will be shown a popup window that asks them to grant you permission to read and write their data.

Which objects they grant you access to depends on the scopes you selected when you created the OAuth app. In our case, the user would only see permissions related to contacts (such as ”View properties and other details about contacts.”) since that’s all we requested when creating our OAuth app.

OAuth is a complicated and nuanced topic, for brevity, we are not going to touch on how to build out an OAuth flow since it is not HubSpot-specific.

Luckily you don’t have to reinvent the wheel on OAuth: Nango offers a free (forever) OAuth client you can easily integrate into your app.

Just follow the steps on the Nango docs and you get a secure, white-label implementation of OAuth for your HubSpot integrations.

Alternatively, you can reference the “Working with OAuth” HubSpot documentation to get implement your own handling of HubSpot’s OAuth flow.

Regardless of whether you build OAuth yourself or leverage Nango, at the end you get an accessToken for your user.

This accessToken is what will allow us to pull and push HubSpot data to the user's account.

Making API requests to the HubSpot API

Now that you are able to authenticate your user, you can begin making API calls to their CRM 🥳. In this section, we explore how to read and write to the HubSpot API in real time.

Reading data from the HubSpot API

Reading from the HubSpot API is pretty straightforward and decently well-documented in the HubSpot API documentation. Each object includes a get, get-all, and batch-get api endpoint giving you a variety of ways to pull HubSpot data.

With that said, here are a few gotchas to watch out for:

  1. Associations: When reading HubSpot data, you’ll need to specify the associations you want to retrieve for an object during each API call.
  2. Properties: Every object property needs to be manually requested during each API call. You can use the properties api endpoint to list all of the properties, including custom ones, that a CRM object has.
  3. Filtering & Sorting: Individual read api endpoints don’t support any sort of filtering or sorting. You’ll need to call the dedicated search api endpoint if you need to apply any filters.

Through HubSpot API

HubSpot API requests to read data

import hubspot from '@hubspot/api-client';

const hubspotClient = new hubspot.Client({
	"accessToken": "YOUR_CUSTOMERS_ACCESS_TOKEN"
});

const properties = ['firstname', 'lastname']; // not a comprehensive set
const associations = ['deals', 'accounts'];

const response = await hubspotClient.crm.contacts.basicApi.getPage(
	undefined, 
	undefined, 
	properties, 
	undefined, 
	associations, 
	false
);

// Todo:
// - Paginate
// - Handle rate-limits & retries
// - Cache data & re-fetch periodically
// - Listen for webhooks on contact changes

With Nango

Nango handles the OAuth & data sync for you. You keep control over which HubSpot data gets fetched and how often.

Reading HubSpot data with Nango

import { Nango } from '@nangohq/node';

const nango = new Nango({ secretKey: process.env.NANGO_SECRET_KEY });

// Get up-to-date contacts from Nango
const contacts = await nango.listRecords({
    providerConfigKey: 'hubspot',    
    connectionId: '', // Which HubSpot account you are fetching
    model: 'Contact'
});

Writing to the HubSpot API

Writing to the HubSpot API is also pleasantly straightforward and well-documented.

With that said, there are still a few gotchas to watch out for:

  1. Associations: Unfortunately, there’s no way to update or create an association through any of the regular object endpoints. You must use the standalone associations endpoints if you update or create associations.
  2. Rate limits: While there is a “batch create”, HubSpot doesn’t support any “batch updates”. Considering the relatively strict rate limits, this can be a real problem if you have a use case that requires updating many objects at once.

Through HubSpot API

Writing data with the HubSpot API

import hubspot from '@hubspot/api-client';
import fetch from 'fetch'

const hubspotClient = new hubspot.Client({
	"accessToken": "YOUR_CUSTOMERS_ACCESS_TOKEN"
});

// Create contact
const response = await hubspotClient.crm.contacts.basicApi.create({
	properties: {
  "firstname": "Jane",
  "lastname": "Doe",
	}
});

// Create Association
const contactId = getId(response)
const path = `/crm/v4/objects/contact/${contactId}/associations/default/account/345`
const association = await fetch(`https://api.hubapi.com/${path}`, {
  "method": "PUT",
  "headers": {
    "accept": "application/json",
    "content-type": "application/json",
    "authorization": "Bearer YOUR_CUSTOMERS_ACCESS_TOKEN"
  }
})

With Nango

Nango handles the multiple API requests required to write this contact to the HubSpot platform. You get full control over the logic & full visibility with Nango’s built-in observability.

Writing HubSpot data with Nango

import { Nango } from '@nangohq/node';

const nango = new Nango({ secretKey: process.env.NANGO_SECRET_KEY });

// Returns newly created contact or detailed error message
const result = await nango.triggerAction(
		'hubspot',
		'',
		'create_contact',
		{
				'firstname': "John",
				'lastname': "Doe",
				'email': "john@doecorp.com"
		}
);

Building a 2-way data sync for your HubSpot integrations

If you are looking to integrate your SaaS product with HubSpot, you probably want to have two kinds of interactions with it:

  1. Syncing data from HubSpot to your SaaS product. This could be contacts, accounts, leads, notes, deals, etc.
  2. Writing data back to HubSpot. For instance updating a field on a contact, creating a new deal, etc.

At first glance this seems simple: Use the API requests we outline above to fetch the data & then write data back to HubSpot as needed.

Let’s take a closer look at each.

Syncing data from HubSpot to your SaaS product

To show HubSpot data in your own product, you usually have to import it first into your own database.

This is due to two reasons:

  1. HubSpot’s API rate limits make it impossible to fetch the HubSpot data in real time from their API
  2. You probably want to associate the HubSpot data with other data from your product (e.g. link a HubSpot contact to a contact in your own product).

Luckily this doesn’t seem terribly difficult. You can just iterate over all the contacts (or deals, accounts, etc.) in HubSpot and store a copy of each in your own database.

As you do this, make sure you account for the following:

  • Rate-limit handling: You are likely to hit rate-limits as part of your import. Make sure you read the response headers, detect the limits and apply appropriate back-off mechanisms. Ignoring rate-limits may get your application blacklisted.
  • Transient failures & retries: Nobody is perfect, not even HubSpot’s API team. Make sure your application can detect temporary errors an retries appropriately (as soon as possible, nobody likes outdated data)
  • Change & deletion detection: After your first sync, you will probably find that some contacts got added, others got changed and a third group was deleted. Make sure your HubSpot data sync can detect all three cases and your application handles them appropriately.
  • Sync status visibility: If your customers cannot see when their HubSpot data was last refreshed it causes a lot of support requests. “Why is John Doe listed as Johnny Doe? I updated that 20min ago in HubSpot!”
  • Bonus: Webhook handling: To avoid even more confusion, make your syncs real-time by listening to the appropriate webhooks from HubSpot. But beware, not all actions trigger webhooks, and there is no guarantee you get a webhook for everything. Only relying on webhooks will lead to gaps in your data.
  • Bonus: OAuth token refreshes: HubSpot’s OAuth tokens expire after ~1h. You will need to refresh the access token to keep making API requests. But beware, a refresh revokes the old access token. Make sure all your data syncs are aware of this and only use the new access token going forward.

Unfortunately, reliable data syncs are not easy to build.

If you want to keep full control over your api integrations (data it syncs, business logic, data models), without having to deal with these complexities, take a look at Nango.

It solves all of these for you and works with 170+ different APIs.

Writing data back to HubSpot

If you are reading data from HubSpot, you likely also want to write data back (e.g. update fields on a contact, create a new deal or account, etc.).

Writes can be a bit simpler: They often only require a single API request and this reduces the amount of things that can go wrong.

But there are still some things you should keep in mind:

  • Rate-limits, retries & transient errors: Just like with fetching data from HubSpot, API requests to write data back can fail at any time. Make sure your application can handle all the different failure appropriately and retries them.
  • Complex write operations: Some write operations require multiple API requests to complete. This means you quickly have entire code sections devoted to dealing with how specific contact fields are best updated in HubSpot. Make sure you encapsulate this complexity.
  • Per-customer configuration: Not all HubSpot setups are the same. Users can create custom fields, change dropdown options and more. Make sure your application has a way to deal with custom configurations for each of your customers.
  • Observability & debugging visibility: Make sure you have alerting in place in case writes start failing for a specific customer. It can also be a good idea to log the exact API request that was sent to the external API, or debugging may become very tricky.

Closing Thoughts

Going into production with your api integrations

You built your HubSpot integration, congrats!

To help you prepare for a successful api integration launch, take a look at our production checklist:

  • Make sure you use a separate OAuth app for production & development
    • This will save you a lot of headache when you need to change your scopes in the future
  • Make sure your customer’s access tokens & refresh tokens are securely stored
    • We recommend at least encrypting them at rest in your database. If they leak an attacker can access all your customer’s HubSpot data!
  • Test your integration with different HubSpot accounts
    • The more edge cases you catch now, the smoother your production experience will be.
  • Log. Everything.
    • Seriously. It is incredibly difficult to reproduce behaviour afterwards if you don’t have visibility into the exact API requests that were sent to HubSpot.

Publishing your integration to the HubSpot Marketplace

Last but least, consider listing your application in the HubSpot Marketplace.

This can be a great place for prospects to discover your product on the HubSpot platform. It will also mark your api integrations as officially certified by HubSpot, which increases trust for a successful api integration.

You can learn more about the publishing process here.

Skip the hassle: Using a platform for product integrations

If you want to integrate your product with HubSpot, but avoid the hassle of building your own api integrations infrastructure, you might want to look into Nango.

Nango gives you a single API for all your api integrations. You get full control over your integrations, without having to dive deep into the quirks of every API (such as how webhooks work for it).

Learn more about Nango on the docs or join the Slack community with 1,300+ developers building product integrations with it.

Robin Guldener
Co-Founder & CEO

Originally an engineer himself Robin has worked on product integrations for 6+ years. Today he is a co-founder at Nango.

Ready to get started?