-
ExploreCategories
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:
- 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.
- An app and registered domain set up on Google's Developer Console. Be sure to get
CLIENT_ID
andCLIENT_SECRET
in your app in order to make API calls. Go here for more info. - Google auth credentials for your users, in order to retrieve their calendar events. You can go here to read about how to get them.
- An Aircall account - sign up here if you don't have one yet.
- 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:
- Get the user's Google Calendar Events via the Google Calendar API
- Subscribe to Event push notifications, in case the user updates their events
- 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!
rubyrequire '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:
json{ "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.
rubyrequire '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: '
/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
ruby# 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.
ruby# config.ru require './app' run App.new
ruby# 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.
rubyclass 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
ruby# 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!