Google Calendar API Returns Busy Times, Not Available Slots — What That Means for Your AI Agent

Nestor Koylyak·March 21, 2026·9 min read

Most developers building an AI scheduling workflow reach for Google Calendar first. It's the obvious choice — everyone uses it, the API is well-documented, and it feels like the problem should already be solved.

It is not quite solved. And the gap is specific enough that it's worth understanding precisely before you build on top of it.

The Google Calendar API is a storage API. It stores and retrieves calendar events. What it does not do — and was never designed to do — is compute availability. It will not tell your agent which slots are open. It will tell your agent which slots are busy. Those are different problems, and the difference matters a lot when an AI agent needs to act autonomously.


What the Google Calendar API Actually Returns

The primary endpoint for availability queries is freebusy.query. This is the closest the Google Calendar API gets to an availability API.

Here is what a request looks like:

const response = await fetch(
  "https://www.googleapis.com/calendar/v3/freeBusy",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      timeMin: "2026-03-24T09:00:00Z",
      timeMax: "2026-03-24T18:00:00Z",
      items: [{ id: "john@company.com" }],
    }),
  }
);
 
const data = await response.json();

And here is what comes back:

{
  "kind": "calendar#freeBusy",
  "timeMin": "2026-03-24T09:00:00Z",
  "timeMax": "2026-03-24T18:00:00Z",
  "calendars": {
    "john@company.com": {
      "busy": [
        {
          "start": "2026-03-24T10:00:00Z",
          "end": "2026-03-24T11:00:00Z"
        },
        {
          "start": "2026-03-24T13:30:00Z",
          "end": "2026-03-24T14:00:00Z"
        }
      ]
    }
  }
}

That is the complete response. A list of busy intervals. Nothing else.

The Google Calendar API does not return available slots. What it returns is busy periods within a time range you specify. Computing what is free from what is busy is left entirely to your backend.


What You Have to Build Yourself

Given the busy intervals above, generating actual bookable slots requires your code to do the following:

Step 1: Define working hours. The API does not know that John works 9am to 6pm. You store that. You enforce that.

const workStart = "09:00";
const workEnd = "18:00";
const slotDuration = 30; // minutes

Step 2: Subtract busy blocks from available time. Take the full working day, remove every busy interval, and compute what remains.

function getFreePeriods(workStart, workEnd, busyIntervals, date) {
  const dayStart = new Date(`${date}T${workStart}:00Z`);
  const dayEnd = new Date(`${date}T${workEnd}:00Z`);
 
  let freePeriods = [{ start: dayStart, end: dayEnd }];
 
  for (const busy of busyIntervals) {
    const busyStart = new Date(busy.start);
    const busyEnd = new Date(busy.end);
 
    freePeriods = freePeriods.flatMap((period) => {
      if (busyStart >= period.end || busyEnd <= period.start) {
        return [period]; // no overlap
      }
      const result = [];
      if (busyStart > period.start) {
        result.push({ start: period.start, end: busyStart });
      }
      if (busyEnd < period.end) {
        result.push({ start: busyEnd, end: period.end });
      }
      return result;
    });
  }
 
  return freePeriods;
}

Step 3: Split free periods into fixed-duration slots. A 90-minute free period with a 30-minute slot duration yields three candidate slots. Each one needs to fit entirely within the free period.

function generateSlots(freePeriods, durationMinutes) {
  const slots = [];
  const duration = durationMinutes * 60 * 1000;
 
  for (const period of freePeriods) {
    let current = period.start.getTime();
    while (current + duration <= period.end.getTime()) {
      slots.push({
        starts_at: new Date(current).toISOString(),
        ends_at: new Date(current + duration).toISOString(),
      });
      current += duration;
    }
  }
 
  return slots;
}

Step 4: Apply business rules. The API has no concept of meeting duration constraints, buffer time between bookings, or which durations a human accepts. You build all of that.

function filterByAllowedDurations(slots, allowedDurations) {
  return slots.filter((slot) => allowedDurations.includes(slot.durationMinutes));
}
 
function addBuffer(slots, bufferMinutes) {
  // remove slots that would start within bufferMinutes of a busy period end
  // your implementation here
}

Step 5: Handle time zones. The API returns UTC. Your human has a local timezone. Your attendee is in a different timezone. If this booking is for a slot in April and you're generating it in January, the UTC offset may be different. You handle all of this.

import { DateTime } from "luxon";
 
function convertToHumanTimezone(slots, humanTimezone) {
  return slots.map((slot) => ({
    ...slot,
    localStart: DateTime.fromISO(slot.starts_at)
      .setZone(humanTimezone)
      .toISO(),
    localEnd: DateTime.fromISO(slot.ends_at)
      .setZone(humanTimezone)
      .toISO(),
  }));
}

By the time you have working slot generation, you have written a non-trivial scheduling library. The Google Calendar API gave you the busy intervals. Everything else is yours to build and maintain.


What the Google Calendar API Does Not Provide

To be explicit about the full scope of what is missing:

CapabilityGoogle Calendar APIWhat you build
Busy periods✓ Returns busy intervals
Available slotsGenerate from inverse of busy
Working hours enforcementStore and apply per human
Meeting duration rulesStore and filter per human
Buffer between meetingsCompute and subtract
Blocked dates (holidays, vacation)Store and apply per date
Timezone-safe slot computationHandle DST per future date
Slot conflict protectionAtomic check-and-insert on booking
Booking lifecycle managementBuild create/cancel/reschedule
Webhook on booking eventsBuild notification system

None of these are criticisms of the Google Calendar API. It does exactly what it was designed to do: store and retrieve calendar data. The gap is that scheduling logic for AI agents is a different problem, and the API was not built to solve it.


Why the Gap Is Bigger for AI Agents Than for Regular Apps

A traditional booking app can paper over most of these gaps because a human is in the loop. The UI shows a calendar, the user picks a slot, the system checks if it's still available, the user confirms. Human judgment fills the gaps.

An AI agent has no human in the loop. It must:

  1. Identify that scheduling is needed
  2. Query availability programmatically
  3. Select a slot based on context
  4. Create the booking atomically
  5. Handle confirmation without manual intervention
  6. React to booking lifecycle events via webhook

Every one of those steps requires the scheduling layer to behave correctly without human correction. If your slot computation returns a slot that overlaps with an existing meeting — because your gap-filling logic has an edge case — the agent books it. The conflict is real. The meeting is double-booked.

At low volume, a bug in your slot logic creates occasional bad bookings. An agent operating at scale creates many bad bookings very quickly.

There is also the race condition problem. If two agents — or two concurrent requests — call your slot endpoint simultaneously and both see the same slot as available, both will try to book it. The Google Calendar API has no built-in mechanism for atomic slot reservation. You need to implement optimistic locking or a transactional check-and-insert to prevent double-booking. This is solvable, but it is non-trivial and easy to get wrong.


When Building on Google Calendar Is the Right Choice

To be fair: building your scheduling layer on top of Google Calendar is the right choice in specific situations.

You should use Google Calendar API if:

  • Your users are already managing their schedules in Google Calendar and you need to respect those existing events
  • You are building a personal assistant that reads a single user's own calendar
  • You need to sync Slotflow or another scheduling system back into a user's Google Calendar for visibility
  • Your scheduling rules are simple and fixed (one person, one timezone, standard hours)

You should not use Google Calendar API as your primary scheduling layer if:

  • An AI agent is making booking decisions autonomously
  • You are managing availability for multiple humans across an organization
  • You need to enforce meeting duration rules, buffers, or blocked dates
  • You need atomic booking creation with conflict protection
  • You need webhooks when booking events occur
  • You need your scheduling layer to work without requiring users to connect their personal Google accounts

The distinction is between using Google Calendar as a data source (reasonable) versus using it as a scheduling engine (a significant build).


A Note on Appointment Schedules

Google Workspace does have a feature called Appointment Schedules, which creates a booking page similar to Calendly. This is worth knowing about, but it does not change the API situation.

Even when a user configures availability through Appointment Schedules, the Google Calendar API still does not expose structured available slots via its API. You still get events and busy status. The booking page is a consumer interface, not an API surface. Accessing it programmatically from an AI agent requires the same slot generation logic described above.


Frequently Asked Questions

Can the Google Calendar API tell me when someone is free? Not directly. The freebusy.query endpoint returns busy intervals — the times a calendar has events. To find when someone is free, your backend subtracts those busy intervals from the person's working hours and generates candidate slots from what remains.

Does Google Calendar have a slots endpoint? No. As of 2026, there is no endpoint in the Google Calendar API that returns pre-computed available time slots. Slot generation is expected to be implemented on your backend.

What is the difference between a calendar API and a scheduling API? A calendar API stores and retrieves events. A scheduling API computes availability — given a person's working hours, rules, blocked dates, and existing bookings, it returns the times that are actually bookable. Google Calendar is a calendar API. Purpose-built scheduling infrastructure handles the availability computation layer.

How does an AI agent query Google Calendar for availability? The standard approach is to call freebusy.query with the calendar ID, a time range, and an OAuth access token. The response returns busy intervals. The agent's backend then runs slot generation logic against those intervals to determine what is bookable. This requires the backend to store and enforce working hours, duration rules, and business constraints that the Google Calendar API does not manage.

What happens if two agents try to book the same slot simultaneously? The Google Calendar API has no built-in atomic reservation mechanism. If two requests see the same slot as available and both attempt to create an event, both may succeed — resulting in a double-booking. Preventing this requires implementing a check-and-insert transaction in your own database before writing to Google Calendar.

Should I sync my scheduling system with Google Calendar? For many use cases, yes. Showing a human their Slotflow bookings in their personal Google Calendar is a good user experience. The sync direction is one-way: your scheduling system is the source of truth for availability and bookings; Google Calendar is a display layer. Building it the other way around — treating Google Calendar as the source of truth and generating slots from it — is the approach that creates the complexity described above.


The scheduling gap in Google Calendar is solvable — developers do it every day. The question is whether building and maintaining that layer is where you want to spend your time, or whether you need that layer to already exist when your agent calls it.

Slotflow is a REST API that handles the scheduling layer — availability rules, slot computation, atomic booking creation, timezone handling, and webhooks — so your agent has a single endpoint to call instead of a library to build. The free tier covers 100 bookings per month, no credit card required.

Get your API key · Read the quickstart