Synchronize agent availability with your Google Calendar
Don't be disturbed with calls when you jump in a meeting!

Select a language:

    In this tutorial, we will create an application that updates a user's availability on Aircall whenever an event in their Google Calendar begins and ends.

    The following video demonstrates how, at the start of My Meeting on Google Calendar, the user's availability on Aircall goes from available to unavailable and vice versa when the event ends a minute later.

     

    Getting started

    Before we begin coding, we need to have:

    1. A server running a backend application. Because it will subscribe to a webhook, we'll need to use something like Ngrok to create an SSH tunnel pointing to our local environment.
    2. An app and registered domain set up on Google's Developer Console. Be sure to get CLIENT_ID and CLIENT_SECRET in your app in order to make API calls. Go here for more info.
    3. Google auth credentials for your users, in order to retrieve their calendar events. You can go here to read about how to get them.
    4. An Aircall account - sign up here if you don't have one yet.
    5. Your API ID and your API Token. You can see your id and get a token in the Company section of the Aircall Dashboard.

    Step by step

    Now that we are all setup, here are the steps we are going to follow:

    1. Get the user's Google Calendar Events via the Google Calendar API
    2. Subscribe to Event push notifications, in case the user updates their events
    3. POST to the /users endpoint on the Aircall API to update a user's availability based on event start and end times

    1. Get a user's calendar events

    We'll want to retrieve a user's Google Calendar events via the Calendar API. For the purposes of this tutorial, we'll fetch all of the user's events right off the bat. This isn't the most efficient solution as the user could have hundreds of events. A better solution would be to schedule a cron job that, once a week, fetches the events for the upcoming week and creates GoogleCalendarEvent records in our database so that we can set availabilities accordingly.

    We're using Ruby and the httparty gem here, but feel free to use whichever language/gem/package you'd like!

    require 'httparty'
    
    # get a list of the user's calendars
    def get_calendar_list
      url = 'https://www.googleapis.com/calendar/v3/users/me/calendarList'
      HTTParty.get(
        url,
        headers: { 'Authorization' => "Bearer #{@user.google_oauth_token}" }
      )
    end
    
    # get all the events from a user's calendar
    def get_events
      # we're assuming the first calendar is the one we want
      calendar = get_calendar_list['items'].first
      return if calendar.nil?
    
      url = "https://www.googleapis.com/calendar/v3/calendars/#{calendar['id']}/events"
      HTTParty.get(
        url,
        headers: { 'Authorization' => "Bearer #{@user.google_oauth_token}" }
      )
    end
    

    The @user variable should be whatever your current user is, and this code assumes they've already authenticated on your app. Check step 3 in the setup for more info on authentication.

    Each event hash will have start and end keys:

    {
      "id": "465qfgq7p5mcvdpm9kfsgn0i3f",
      "summary": "My Meeting",
      "status": "confirmed",
      "start": {
          "dateTime": "2018-03-21T14:00:00+01:00"
      },
      "end": {
          "dateTime": "2018-03-21T14:15:00+01:00"
      }
      ...
    }
    

    You can save these to your database, perhaps as GoogleCalendarEvent records so that your application (with the help of a cron job) can later know when to sync the user's availability.

    2. Subscribe to event push notifications

    In case a user changes any events on their calendar, we're going to subscribe to Calendar API Push Notifications so we can keep the start and end times updated.

    require 'httparty'
    
    def subscribe_calendar_notifications
      url = "https://www.googleapis.com/calendar/v3/calendars/#{@user.google_calendar_id}/events/watch"
      HTTParty.post(
        url,
        headers: { 'Authorization' => "Bearer #{@user.google_oauth_token}" },
        body: {
          id: 'unique-channel-id',
          type: 'web_hook',
          address: '<your-ngrok-url>/webhooks/google/notifications'
        }
      )
    end
    
    

    Make sure id is unique within your app, and the address should be whatever your current NGROK url is, along with a path to receive webhook events.

    You only have to subscribe to a particular calendar once, so you might want to do this right after the user authenticates their Google account. Let's say this happens in a callback method within GoogleController

    # app/controllers/google_controller.rb
    
    def auth_callback
      if user_authenticated? # logic to verify successful authentication + save credentials
        subscribe_calendar_notifications
      end
    end
    

    Now that our webhook is subscribed, we need to handle the requests that we receive. Here, we'll demonstrate how to set up the Webhook as a Rack app, just to give you an idea on how to handle requests.

    # config.ru
    
    require './app'
    
    run App.new
    
    # app.rb
    
    require 'rack'
    require 'json'
    
    class App
      def initialize
        @app = Rack::Builder.new do
          map '/webhooks/google/notifications' do
            run Proc.new { |env|
              req = Rack::Request.new(env)
    
              body = JSON.parse(req.body.read) if req.body.read.present?
              headers = {}
              env.select {|k,v| k.start_with? 'HTTP_'}
                 .collect {|key, val| [key.sub(/^HTTP_/, ''), val]}
                 .each {|key, val| headers[key] = val}
    
              case headers['X_GOOG_RESOURCE_STATE']
              when 'sync'
                # we receive this message to indicate that notifications are starting,
                # and could retrieve all events here if we wanted to
                puts 'SYNC!'
              when 'exists'
                # the calendar has changed, so we would want to retrieve all events
                # again and verify that the start and end times for each event haven't
                # changed, and update our records if they have
              end
    
              ['200', {'Content-Type' => 'text/html'}, ['ok']]
            }
          end
        end
      end
    end
    

    3. Update a user's availability via the Aircall API

    Now that have a user's Calendar events and we're sure we have up-to-date start and end times, we can set up workers to update their availability on Aircall via the API.

    It's up to you how you set up your application's cron jobs, so we'll just give you an example of a scheduler that runs Sidekiq workers AvailabilityWorker for all events for the current day. We'll use the clockwork gem, a scheduler process that is easily configurable to spawn workers when we need them. Read here if you're unfamiliar with cron jobs.

    class AvailabilityWorker
      include Sidekiq::Worker
    
      def perform(user_aircall_id, event_end_time, is_occurring = true)
        status = is_occurring ? 'unavailable' : 'available'
    
        url = "https://api.aircall.io/v1/users/#{user_aircall_id}"
        HTTParty.post(
          url,
          basic_auth: { username: ENV['AIRCALL_API_ID'], password: ENV['AIRCALL_API_TOKEN'] },
          availability_status: status
        )
    
        # queue another worker for when the event ends
        AvailabilityWorker.perform_at(event_end_time, user_aircall_id, event_end_time, false) if is_occurring
      end
    end
    
    # clock.rb
    
    require 'clockwork'
    
    include Clockwork
    
    every 1.day, 'job.calendar_availabilities' do
      events = calendar_events_for_user # logic to retrieve events for one or many users
      events.each do |event|
        # queue the worker to spawn once the event starts
        AvailabilityWorker.perform_at(event.starts_at, event.user_aircall_id, event.ends_at, true)
      end
    end
    

    And voilĂ ! Now your user's Calendar meetings can reflect their availability status on Aircall, preventing unnecessary missed calls. There's plenty more possible with the Google Calendar API so feel free to dig deeper with this integration!

    Error handling has not been implemented in the above code examples to make the code easier to read.
    Don't go deploying this in a production environment!

    We wrote other tutorials to help you out
    building awesome integrations

    Discover them now!