Calendar API Integration for Real-Time Availability
Calendar integration design covering Google Calendar, Microsoft Graph, recurring events, booking conflicts, and time zones.
Calendar availability depends on provider data, recurring-event exceptions, working hours, buffer times, and concurrent bookings. An integration needs to reconcile these inputs before presenting a slot as bookable.
The sections below separate provider capabilities from availability rules and booking coordination that your application must implement.
Requirements for Availability Calculation
The core task is: given a time window and a set of resources (users, rooms, staff), determine which slots within that window are genuinely available for booking. This requires:
- Fetching existing events from each resource's calendar
- Applying your own availability rules (working hours, buffer times, booking lead time)
- Subtracting blocked periods (existing bookings, vacations, manual overrides)
- Returning a set of bookable slots with accurate time zone information
- Preventing two concurrent requests from booking the same slot
Step 5 is the one that cannot be handled entirely through calendar APIs — it requires state on your side.
Google Calendar and Microsoft Graph: What You Get
The two dominant calendar APIs are Google Calendar (part of Google Workspace) and Microsoft Graph (covering Outlook and Exchange). Both provide:
- Event listing: Retrieve events within a time range, including recurring event instances
- Free/busy queries: A faster, less data-intensive endpoint that returns blocked windows without event details
- Event creation: Write confirmed bookings back to the calendar
- Webhooks/push notifications: Receive callbacks when calendar data changes (Google calls these push notifications via watch channels; Microsoft Graph calls them subscriptions)
Free/busy queries are the right tool for availability computation. They are faster than full event listing and return less data. Use full event listing only when you need event details — for example, to display what is blocking a slot in an admin view.
OAuth Scopes and Token Management
Both providers require OAuth 2.0 for calendar access. Request the minimum scope that covers your use case:
- For read-only availability checks:
https://www.googleapis.com/auth/calendar.readonly(Google) orCalendars.Read(Microsoft) - For writing bookings back:
https://www.googleapis.com/auth/calendar.events(Google) orCalendars.ReadWrite(Microsoft)
Store refresh tokens securely and rotate access tokens proactively. Calendar tokens can expire or be revoked — your system needs to detect this and prompt re-authentication without silently failing to fetch availability.
Handling Recurring Events Correctly
Recurring events are where calendar API integrations break in subtle ways. A recurring meeting that blocks Tuesday afternoons for the next year will appear as a single event with a recurrence rule, not as individual instances. When you query for free/busy data, most APIs expand recurring events for you within the query window — but verify this for each provider and API version you use.
Watch for these edge cases:
- Modified instances: A recurring event where one instance has been moved or cancelled. The API returns this as an exception to the recurrence rule. Naive implementations miss the exception and either block or free a slot incorrectly.
- Declined invites: An event a user was invited to but declined. Some APIs include declined events in free/busy; others do not. Query behavior depends on the provider and the calendar's sharing settings.
- All-day events: These do not have explicit times, only a date. Whether they block availability is a product decision you need to make and implement explicitly.
Time Zone Handling
Store concrete booking instants in UTC, and retain the IANA time zone and local-time rules needed for recurring schedules. All-day events use dates, while recurring events require a time zone for expansion. Google Calendar event reference.
Practical rules:
- Always include explicit UTC offsets in API requests and responses. Never send bare local times.
- Store the user's IANA time zone identifier (e.g.,
America/Chicago, notCST) and use it to compute local times. Named time zones handle daylight saving transitions correctly; fixed offsets do not. - When computing available slots for display, convert slot start and end times to the viewer's time zone — which may differ from the resource's time zone.
Preventing Double Bookings Under Concurrent Load
Calendar APIs are not transactional. If two requests hit your system simultaneously and both query the calendar API before either writes a booking, both will see the slot as available and both may attempt to create a booking.
The fix lives in your own database, not in the calendar API:
- Maintain a booking table in your own database as the authoritative record of confirmed bookings.
- Before writing a new booking, acquire a row-level lock on the resource record for the relevant time window (using
SELECT FOR UPDATEin PostgreSQL, for example). - Perform the conflict check inside the transaction.
- Write the booking if no conflict exists, then roll back if one does.
- After the transaction commits, write the event to the external calendar asynchronously.
This means your availability check at slot selection time is optimistic — it reflects the last known state of the calendar. The authoritative check happens at write time. Surface clear messaging to users when a slot becomes unavailable between selection and confirmation.
Webhook Architecture for Keeping Availability Current
Polling calendar APIs for changes is slow and API-quota-expensive. Use webhooks (push notifications in Google's terminology, subscriptions in Microsoft's) to receive change notifications and invalidate your availability cache when the underlying calendar changes.
Key implementation points:
- Renew subscriptions using the expiration returned by each provider. Google watch-channel limits can constrain the requested expiration; Microsoft Graph lifetimes depend on the resource and notification mode. Google push notifications, Graph subscription lifetimes.
- Validate webhook authenticity. Google includes a
X-Goog-Channel-Tokenheader you can use to verify the source. Microsoft provides a client state value you set at subscription time and receive back with each notification. - Process notifications asynchronously. Webhooks should be acknowledged immediately (return HTTP 200) and the actual processing (cache invalidation, availability recomputation) should happen in a background job.
Provider Abstraction
If you need to support both Google Calendar and Outlook, build a thin abstraction layer that exposes a consistent interface — getFreeBusy(resourceId, startTime, endTime), createEvent(resourceId, event), deleteEvent(resourceId, eventId) — and implements each against the relevant provider API. This makes it possible to add providers later (iCal, Nylas, etc.) without rewriting the availability logic.