How to Integrate The Google Calendar API Into Your App

How to Integrate The Google Calendar API Into Your App

Learn about what it takes to integrate the Google Calendar API into your app, and discover how Nylas makes it easy

Ben Lloyd Pearson | April 9, 2020

The Google Calendar API enables developers to add full calendar data and functionality into their app using a REST interface, or through one of the client libraries Google offers for languages like Java, Python, PHP, JavaScript, and more.

Do you want to integrate Google Calendar accounts directly into your app? This article will cover the major components of the Google Calendar API and explain what it takes to build a full integration with Google Calendar accounts. It will also demonstrate how the Nylas Communications Platform abstracts away much of the complexity of building a direct integration with the Google Calendar API to enable you to build your calendar integration much more quickly and efficiently.

Connect Google Accounts to Your App

Before you can access a Google Calendar account, you will need to authenticate the account with the appropriate permissions. All Google APIs use OAuth 2.0 for account authentication and authorization, which establishes a login process where your app negotiates with the Google Identity Platform to receive an access token for user accounts. This token provides limited access to user resources based on the scopes the user consented to as part of the authentication process. Head over to the Google Identity API docs to learn more about the various methods that are available to authenticate Google accounts.

Alternatively, Nylas Hosted Auth auto-detects Google accounts, even for domains other than gmail.com, and prompts users to sign in and accept the permissions your app needs. Your user’s credentials are stored safely on our SOC 2 Certified infrastructure, and Nylas provides an access token your app can use for Google Calendar data and functionality.

The Nylas Hosted Auth platform

Google Calendars and Events

The main organizational components of the Google Calendar API are calendars and events.

Calendars are a collection of related events that include relevant metadata like name, description time zone, and more. Each Google account has a primary calendar that contains the user’s email address as its name; this calendar can’t be deleted by the user, but it can be shared with other users. Users are also able to create any number of secondary calendars and these can be modified, deleted, and shared with any number of users, this can include:

  • Personal and work calendars
  • Calendars that belong to other people in the user’s GSuite organization
  • Shared calendars that include multiple people from the same team or company to events
  • Custom calendars the user has created to track specific types of events

The Google Calendar API also includes a CalendarList object: a collection of all calendars to which a user is subscribed. Use the CalendarList endpoint when you want to access user-specific calendar properties, such as default reminders and background/foreground colors. Use the Calendar object when you need to create and delete calendars, or set global properties that are shared across all users with access to the calendar, like the title and default time zone.

Events are objects that are associated with a specific time or date range and include information like title, description, location, attachments, and attendees, and they can be set for a specific time span, or they can be set for an entire day. Every event on a Google Calendar is associated with one or more calendars, and all events have an organizer with access to the primary  copy of the event and any number of attendees who have their own secondary copies of the event. Each of these event copies will have their own unique IDs for each calendar it appears on, but they will all have an identical iCal UID.

Calendars and Events in Nylas

The Nylas Calendar API connects to 100% of calendar providers, including Google Calendar. Nylas standardizes data and functionality into a predictable, easy-to-use JSON format that allows you to enable full calendar functionality within your app, no matter the provider your users prefer. Similar to the Google Calendar API, The Nylas Calendar API is organized into calendars and events.

With one simple request to the Nylas Calendar API, you can return the entire list of calendars the user has access to. This is an example of what this would look like for a Google Calendar account:

$ curl -X GET 'https://api.nylas.com/calendars' -H 'Authorization: Bearer ACCESS_TOKEN'
[
    {
        "description": null,
        "id": "67qmz3fuk9wf***",
        "name": "[email protected]",
        "account_id": "bh1vu31mw9ap***",
        "object": "calendar",
        "read_only": false
    },
    {
        "description": "Emailed events",
        "id": "b4xm1jjibrxky***",
        "name": "Emailed events",
        "account_id": "bh1vu31mw9a***",
        "object": "calendar",
        "read_only": true
    },
{
        "description": "A shared calendar of mathematics industry conferences",
        "id": "h4rm1jjibrzd7***",
        "name": "Mathematics Conferences",
        "account_id": "bh1vu31mw9a***",
        "object": "calendar",
        "read_only": true
    }
]

In this example, we make a GET request to /calendars, passing the access token for the user account in the request header. The response is a JSON body that contains a list of the user’s three calendars. The first two are calendars are included by default with all Google accounts: the primary user calendar, which has the user’s email address as the name, and the Emailed Events calendar, which includes all events to which the user has been invited via email. 

The last calendar is a custom calendar used to track conferences that has been shared to our user by someone else. Notice that our user is only capable of editing the first calendar in this list, the other two have a value of true for the read_only attribute indicating the user only has read access. 

Now, let’s see what one of the events on the shared Mathematics Conferences looks like.

$ curl -X GET 'https://api.nylas.com/events/{id}' -H 'Authorization: Bearer ACCESS_TOKEN' 
[
    {
        "account_id": "bh1vu31mw9a***",
        "busy": true,
        "calendar_id": "h4rm1jjibrzd7***",
        "title": "Monthly Analytical Engine Meetup",
        "description": "This is our normal monthly meetup to discuss progress being made on the Analytical Engine.",
        "ical_uid": "[email protected]",
        "id": "c7n5vl6dhbdeq***",
        "location": "London",
        "message_id": null,
        "object": "event",
        "owner": "Charles Babbage <[email protected]>",
        "participants": [
            {
                "comment": "You'll never believe what I've learned about algorithms!",
                "email": "[email protected]lgoprime.com",
                "name": "Ada Lovelace,
                "status": "yes"
            },
            {
                "comment": null,
                "email": "[email protected]",
                "name": "Charles Babbage",
                "status": "yes"
            },
            {
                "comment": "Apologies, but I have more pressing matters this month",
                "email": "[email protected]",
                "name": "Albert Einstein",
                "status": "no"
            }
        ],
        "read_only": true,
        "status": "confirmed",
        "when": {
            "end_time": 1478568600,
            "object": "timespan",
            "start_time": 1478565000
        }
    }
]

In this example, we make a GET request to the /events/{id} endpoint to return a JSON payload that represents a single event. As you can see, this payload has all of the elements you’d expect to see in a calendar event, including the title, description, list of participants with indicated status and comments, and date and time information. 

Free/Busy Detection

The Google Calendar API Freebusy endpoint enables you to view when a user is free or busy depending on whether or not events exist during a specified time frame. This is a special form of read access that Google accounts can have that shows only the start and end times of events where a user is marked busy, it provides no other data about the events.  One major benefit free/busy detection brings is the ability to compare multiple calendars and identify time slots where both calendars have availability without revealing any information about the events on the calendars.

Similarly, The Nylas Calendar API provides free/busy information via POST requests to the /free-busy endpoint. To check the free/busy status of a users calendar, pass a start and end time, and the user’s email to the /free-busy endpoint. It will return a list of time_slot objects that indicate timespans where the user is marked busy:

curl -X POST "https://api.nylas.com/calendars/free-busy" \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-d "{
        \"start_time\":\"1409594400\",
        \"end_time\":\"1409598000\",
        \"emails\": [\"[email protected]\"]
} "

[ 
  {
   "object": "free_busy",
   "email": "[email protected]",
   "time_slots": [
      { 
        "object": "time_slot",
        "status": "busy",
        "start_time": 1409594400,
        "end_time": 1409598000
      },
      { 
        "object": "time_slot",
        "status": "busy",
        "start_time": 1409598000,
        "end_time": 1409599000
      }
    ]
  }
]

Recurring Events

Google Calendar has two types of events: single and recurring.  Single events occur once, while recurring can repeat in a myriad of different ways.  When managing recurring events, it’s important to be aware of how they are represented internally.  When creating a recurrence, two different types of events are created.  The first is an event that represents the series and stores both the recurrence field, as defined in RFC 5545 and the original start & end times.

The recurrence field defines things like the frequency at which an event will repeat (daily, weekly, monthly, etc.), the interval (every day, every other week, etc.), the number of times an event should repeat, and the days of the week for which an event should be repeated. Take a look at the documentation on recurring events to learn more about how these work.

By default, Nylas only returns the original event, not all of the recurring events. However, it’s extremely easy to return all event recurrences by passing expand_query=’true’ to the as a query parameter to the /events endpoint. In the following example, notice the additional recurring event info embedded into the id field after the underscore and the reference to the original master event’s id in the master_event_id field for each event.

curl -X GET \
  'https://api.nylas.com/events?expand_recurring=true' \
  -H 'Authorization: Bearer ACCESS_TOKEN'
[
    {
        'id': '5soti3r111c0f35dllc0iz2zb_20200317T170000Z', 
        'account_id': '223obnv***', 
        'title': 'Team Stand Up', 
        'description': 'This is our daily stand up!',
        'location': 'The Invention Lab',
        'read_only': True, 
        'when': {
            'start_time': 1584464400,
            'end_time': 1584465900, 
            'object': 'timespan'
        }, 
        'busy': True, 
        'participants': [
            {
             'comment': None, 
             'email': '[email protected]', 
             'name': 'Thomas Edison'', 
             'status': 'yes'
            },
            {
             'comment': "Can't wait to get this started!", 
             'email': '[email protected]', 
             'name': 'Leonardo Davinci', 
             'status': 'yes'
            },
            {
             'comment': None, 
             'email': '[email protected]', 
             'name': 'Stephanie Kwolek', 
             'status': 'yes'
            },
        ], 
        'calendar_id': '5idi2a6***', 
        'status': 'confirmed', 
        'master_event_id': '5soti3r111c0f35dllc0iz2zb', 
        'owner': ' [email protected]', 
        'object': 'event'
    },
    {
        'id': '8dg2y9scccgacw519fd5iz89h_20200317T170000Z',  
        'account_id': '223obnv***', 
        'title': 'Team Stand Up', 
        'description': 'This is our daily Standup!', 
        'location': 'The Invention Lab', 
        'read_only': True, 
        'when': {
            'start_time': 1584550800,
            'end_time': 1584552600, 
            'object': 'timespan'
        }, 
        'busy': True, 
        'participants': [
            {
             'comment': None, 
             'email': '[email protected]', 
             'name': 'Thomas Edison'', 
             'status': 'yes'
            },
            {
             'comment': None, 
             'email': '[email protected]', 
             'name': 'Leonardo Davinci', 
             'status': 'yes'
            },
            {
             'comment': 'I have a conflict with another meeting.', 
             'email': '[email protected]', 
             'name': 'Stephanie Kwolek', 
             'status': 'no'
            },
        ], 
        'calendar_id': '5idi2a6***', 
        'status': 'confirmed', 
        'master_event_id': '5soti3r111c0f35dllc0iz2zb', 
        'owner': '[email protected]', 
        'object': 'event'
    },
    {
        'id': 'bjds9az3wmaizmd5eaq5q33lr_20200317T170000Z',  
        'account_id': '223obnv***', 
        'title': 'Team Stand Up', 
        'description': 'This is our daily Standup!', 
        'location': 'The Invention Lab', 
        'read_only': True, 
        'when': {
            'start_time': 1584637200,
            'end_time': 1584639000, 
            'object': 'timespan'
        }, 
        'busy': True, 
        'participants': [
            {
             'comment': None, 
             'email': '[email protected]', 
             'name': 'Thomas Edison'', 
             'status': 'yes'
            },
            {
             'comment': None, 
             'email': '[email protected]', 
             'name': 'Leonardo Davinci', 
             'status': 'yes'
            },
            {
             'comment': None, 
             'email': '[email protected]', 
             'name': 'Stephanie Kwolek', 
             'status': 'yes'
            },
        ], 
        'calendar_id': '5idi2a6***', 
        'status': 'confirmed', 
        'master_event_id': '5soti3r111c0f35dllc0iz2zb', 
        'owner': '[email protected]', 
        'object': 'event'
    }
]

How Nylas Abstracts Away Complexity

The primary benefit of building your Google Calendar integration with Nylas is that we abstract away some of the complexities of working with the Google Calendar API. Let’s take a look at some of the more common stumbling blocks encountered when working with the Google Calendar API and how Nylas helps smooth them out. We’ll demonstrate this functionality with the Nylas Python SDK, but we also provide SDKs for Java, Node.js, and Ruby.

Know the Difference Between Update and Patch

The update method for events uses HTTP PUT, meaning it completely replaces an existing event with a brand new event that has matching details, except for the event id and the values you specify in the update method. If you need to keep track of your event after making an update with this method, you need to account for the fact that the event’s id will change. If you want to keep the existing event id, you need to use the patch method instead, which follows the conventions of HTTP PATCH.

Nylas simplifies this by allowing you to make modifications to existing events via PUT requests to the /events/{id} endpoint. The resulting changes will not create an entirely new event, but instead, only updates the fields you modify. This is how it would look with the Nylas Python SDK.

from nylas import APIClient
nylas = APIClient(
    CLIENT_ID,
    CLIENT_SECRET,
    ACCESS_TOKEN
)

# Get an event by specifying its ID
event = nylas.events.get("{id}")

# Change the location of the event
event.location = "My House!"

# Save the event to the user's calendar and send email notifications to all participants
event.save(notify_participants='true')

Events as First Class Objects

You’re only able to make GET requests to event resources from the Google Calendar API as second class objects, with the Calendar ID being the first class object. This means you must always know which calendar the event exists on before you can request it. The Google Calendar API compensates slightly for this by allowing you to access the user’s primary calendar by passing ‘primary’ as the ID, but this doesn’t help you if you need to search for events across secondary calendars.

With the Nylas Calendar API, events are first class objects, meaning you can access them without prior knowledge of the calendar they are contained in. If you need to search for events on a specific calendar, you can pass calendar_id={id} as a query parameter to the /events endpoint. Here’s what this looks like with our Python SDK.

from nylas import APIClient
nylas = APIClient(
    CLIENT_ID,
    CLIENT_SECRET,
    ACCESS_TOKEN
)
# Return all of the events a user has across all of their calendars
all_events = nylas.events.all()

# Return events only for a specific calendar
my_calendar_events = nylas.events.where(calendar_id='{id}')

Moving Events Between Calendars

The Import and Move methods are both related to sending events from one calendar to another, but they do so in very different ways. Import should more accurately be named duplicate because it doesn’t create a link between the original event and the copied event. Import expects the calendar ID to be passed as a path parameter, and the event details to be passed in the body.

Move, on the other hand, changes the event’s organizer which effectively relinquishes the event from the original calendar. It requires you to pass the calendar ID and event ID as path parameters, but unexpectedly requires you to pass the destination calendar ID as a destination query parameter.

Nylas makes it very easy to manage Google Calendar Events across any number of calendars. If you want to copy an event from one calendar to another, you simply create a new event that has the appropriate calendar ID for the new calendar you want the event to appear on. If you want to move an event, all you need to do is make a DELETE request to the /events/{id} endpoint to remove the event from the original calendar after it has been copied. Alternatively, if you need to deduplicate copies of a single event, Nylas makes this easy via the iCal UID.

Here’s how this works with the Nylas Python SDK:

from nylas import APIClient
nylas = APIClient(
    CLIENT_ID,
    CLIENT_SECRET,
    ACCESS_TOKEN
)
# Find the event you want to copy by passing its ID to events.get()
existing_event = nylas.events.get("{id}")

# Create the new event and assign it a calendar_id that is different than the original
new_event = existing_event
new_event.calendar_id="{id}"

# Save the event to the user's calendar, but don't notify participants since we're making a change that only affects our user.
new_event.save(notify_participants='false')

# Optional: if you want to move the event, you simply need to delete the original event
nylas.events.delete(existing_event.id, notify_participants='false')

Scheduling Across Timezones

Any application recording events across regions must contend with the tricky problem of normalizing time.  The Google Calendar API uses the following semantics: report in the user’s selected time zone, unless your API request specifies otherwise.  For applications that only operate in the context of a single user’s calendar, this is convenient behavior.  However, if you need to compare events across different calendars or users (e.g. a meeting scheduler), you should always provide a time zone parameter or be sure to normalize events in application code.

This is an easy mistake to make, as there is no global setting in the client libraries to always use UTC.  Unless always told otherwise in every request, the API will happily report localized datetimes to your application, potentially resulting in madness.

The Nylas Calendar API normalizes all time representations to either a date representation or epoch time representation. Both can be expressed as a single instance or a span that includes all times/dates between two separate date and time representations. This makes it easier to manage the timing of events across multiple calendars and timezones. Here’s what this looks like with the Nylas Python SDK.

from nylas import APIClient
nylas = APIClient(
    CLIENT_ID,
    CLIENT_SECRET,
    ACCESS_TOKEN
)
event = nylas.events.create()
# An event that happens at one specific moment in time (epoch timestamp)
event.when = {"time": 1577829600}

# An event that spans between two points in time (epoch timestamps)
event.when = {"start_time": 1577829600, "end_time": 1577840400}

# An event that takes up one entire day
event.when = {"date": "2020-01-01"}

# An event that spans between two separate dates
event.when = {"start_date": "2019-08-29", "end_date": "2019-09-01"}

If you need to express events in the user’s timezone, most languages have numerous libraries that enable you to detect the user’s time zone and convert the epoch time stamp to a more meaningful representation of time. Furthermore, Nylas ensures that any events you create or modify with the Nylas Calendar API will be properly synced back to Google in the appropriate timezone for the user.

Take Your Calendar Integration Further With Nylas

Why Stop with Google Calendar? Nylas supports 100% of email, calendar, and contacts providers out of the box, enabling your users to keep using their calendar provider of choice. This post has only covered a fraction of the benefits the Nylas Communications Platform provides, let’s take a look at a few of the other reason why you should build your calendar integration with Nylas.

About the Author

Ben is the Developer Advocate for Nylas. He is a triathlete, musician, avid gamer, and loves to seek out the best breakfast tacos in Austin, Texas.

Ready to Start Building?