How to Import HubSpot Meetings from a Calendar

Share on facebook
Share on twitter
Share on linkedin

HubSpot is an incredible tool to help you track your sales activities and identify how long it takes to set meetings with prospects. From there, you can calculate if you are reaching out to the right amount of new prospects to close your deals. Here’s how to import HubSpot meetings in minutes.

The problem is when you’re switching over to HubSpot after not logging those meetings over the past years.

Don’t worry, you can still collect that data by exporting and backlogging your Google Calendar into HubSpot.

Importing Calendar Libraries

As always, you want to make sure you have the right tools for the job.

The json library lets you turn strings into JSON. JSON stands JavaScript Object Notation which is a standardized format that most software return data as.

The pprint library pretty prints JSON so you can read it as it is difficult to read.

The urllib library allows you store a dictionary of parameters into a request URL.

The ics library allows you to process calendar files using a parser just like Beautiful Soup, an HTML parsing library. It is very important for this project.

Some libraries that we use often are Pandas, Datetime, SimpleJson, and Requests.

import json
import pprint
import urllib
import ics
import pandas as pd
import datetime
import simplejson
from pandas import json_normalize
import requests

Load Your Calendar Data

Using the ics library, you will be able to parse any file with the file type .ics. For some sample data, I recommend that you go to your Google Calendar that you regularly use and export the data.

If you go to your calendar, you will see a gear. Click on it and click Settings.

Click the Gear and Settings on the top right of your Google Calendar
export Google Calendar data
Click on Import & Export at the Bottom

Click the Export button and you will receive your Google Calendar file. Open up your PyCharm project and copy the file over with the title “your_calendar.ics”.

We will read the file in and pass it into a Calendar object. We will get the events by getting the events variable from our new list.

data = open("your_calendar.ics").read()
events = ics.Calendar(data).events

Setup the HubSpot API

Now that we have every event from your Google Calendar in a list, we want to integrate into HubSpot to import meetings.

First, you will need to pull your API key.

Access HubSpot API Key

In order to find your API Key, you will want to click on the Setting gear in the top right corner. It is to the left of your notifications bell.

After that, you want to click “Integrations” on the left submenu. Inside that menu, click on API Key. If you don’t have an API key, you will want to click a “Create an API Key” and copy it into your Python file.

apikey = 'YOUR_API_KEY' # Insert Your API Key here
meeting_url = '' + apikey

We will also make a dictionary called “headers” where we create a dictionary that holds the “Content-Type” and “Accept-All” with “application/json” as the value.

headers = {'Content-Type': 'application/json', 'Accept-All': 'application/json'}

Create Function for Creating Contacts

As we go through each event in the Google Calendar, we will get the emails that are attached to that event. Sadly, unless they are in HubSpot, we won’t be able to add meetings to the contact.

Next, we are going to create a for loop where we iterate through every single event and perform the following actions:

  1. Add the attendee emails to a list
  2. Find the contact in HubSpot if it exists
  3. Reformat Start Times and End Times to HubSpot’s time
  4. Create a New JSON object
  5. Send JSON to the webhook and print the result

Iterate Through Each Event

all_emails = []
for event in events:

Please keep in mind while replicating this code that the rest of the code is running inside this event except for when I state that it is out of the for loop.

Store the Event Data

The first step will be to create variables from each event within the for loops. We will break down our event object to get its name, description, duration, start time, end time, and attendees list.

We also want to create a list of IDs inside this for loop for the contacts.

name =
summary = event.description
duration = event.duration
start_time = event.begin
end_time = event.end
attendees = event.attendees
attendee_emails = []
contact_ids = []
company_ids = []
deal_ids = []

Find the Contacts in the Event

In order to attach the meetings to the right contacts, we will need to iterate through each email associated with the event and find the contact id of that email.

Inside of our initial for loop, we will want to create a new For Loop that goes through each attendee in the attendees list.

for attendee in attendees:

For each attendee, we want to append their email to our list of attendees.


Next, we want to find the contact in HubSpot that is related to that contact in HubSpot. If they are not in HubSpot, we want to create a contact.

You can do this two different ways.

  1. Use the HubSpot contacts export or pull them using the API
  2. Find the Contact, Create if it doesn’t exist

We will use the second step due to simplicity, but the first step would be faster, yet more advanced.

First, we want to create our url to call using the HubSpot API, passing the email of the attendee through and our API Key.

We want to then call a GET request to that URL. This will return either a 200 success code if it exists or a 404 error if it does not. If we receive a 404, we want to create the contact. If we receive a 200 success code, we want to get the ID and add it to our list.

url = '' + + '/profile?hapikey=' + api_key
response = requests.get(url)
if response.status_code == 404:
    endpoint = '' + api_key
    headers = {}
    headers['Content-Type'] = 'application/json'
    data = json.dumps({
        "properties": [ {
           "property": "email", "value":
    response =, data=data, headers=headers)
    response = response.json()
    vid = response['vid']
   response = response.json()
   vid = response['vid']

Reformat Start Times and End Times

Before we can add this meeting to the contact’s VID in HubSpot, we need to reformat the times so that HubSpot accepts it. In this case, I am reformatting based on how Google Calendar has theirs formatted.

Please keep in mind that I hacked the datetimes a bit to make it easier. Datetimes are a mess.

I will walk through how we will deal with start time and then we will use the same treatment on our times.

First, we want to turn our datetime into a string and replace the T symbol with a space. We will do this by wrapping our time in the str() initializer followed by a replace statement with the symbol we want to replace and what we want to replace it with.

start_time = str(start_time).replace('T', ' ')

Next, we need to remove the + and – signs that depict AM and PM.

start_time = start_time[:start_time.find('+')]
if start_time.find('00-') != -1:
    start_time = start_time[:start_time.find('00-')+2]

Now that we have removed some of the harder to convert symbols from our datetimes, we can use the strptime method to convert this String into a DateTime object. We will pass in the datetime along with the pattern we want to parse.

  • %Y represents a year in 4 digits like 2020
  • %m represents month with 2 digits like 05
  • %d represents day with 2 digits like 20
  • %H represents hour as 2 digits in military form like 23
  • %M represents minutes as 2 digits like 34
  • %S represents seconds as 2 digits like 40
start_time = datetime.datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S')

You now have a datetime object that you can turn into a timestamp. A timestamp is your datetime object represented in seconds since a specific date in 1969 called epochs.

One nuance to understand is that HubSpot only takes in Milliseconds, so remember to multiply by 1000.

start_time = start_time.timestamp() * 1000

You now have your start time in a format that HubSpot will accept. Let’s run it on end time as well.

end_time = str(end_time).replace('T', ' ', 1)
end_time = end_time[:end_time.find('+')]
if end_time.find('00-') != -1:
    end_time = end_time[:end_time.find('00-') + 2]

end_time = datetime.datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S')
end_time = end_time.timestamp() * 1000

Finally, let’s print out the start time, end time, and summary to ensure they’re in the right format before sending them over.


Create a Meeting in JSON

Inside of the for loop, we want to create JSON that will be sent to HubSpot’s endpoint for every single event in your Calendar.

owner_id = 'YOUR_OWNER_ID'
payload = json.dumps({
     "engagement": {
         "active": True,
         "ownerId": owner_id,
         "type": "MEETING",
         "timestamp": start_time
    "associations": {
         "contactIds": contact_ids,
         "companyIds": company_ids,
         "dealIds": deal_ids,
         "ownerIds": [],
         "ticketIds": []
    "metadata": {
         "title": name,
         "startTime": start_time,
         "endTime": end_time,
         "body": summary
response =, data=payload, headers=headers)

Clean Up Calendar Emails & Export

We now have all of our data into HubSpot, but we may want to have a list of all the email addresses. This will be super simple as we will simply take our list and store it into a column of a DataFrame. Then we will call the “to_csv” method and store our emails as a CSV called “all_emails.csv”.

emails = pd.DataFrame()
emails['Email'] = pd.Series(all_emails)
emails.to_csv('all_emails.csv', index=False)

Please keep in mind that this assumes that there are no meetings inside HubSpot currently and used specifically as a use case to backlog a HubSpot if a client is moving over to HubSpot after years of business.

A more advanced solution would include deduplicating meetings using the Engagements API.