Get Free/Busy Status
Query free/busy information for one or more Google Calendars
Source Code
/**
* Query free/busy information for one or more Google Calendars
* @param {string} timeMin - Start datetime in RFC3339 format (e.g., '2025-12-15T09:00:00-08:00')
* @param {string} timeMax - End datetime in RFC3339 format (e.g., '2025-12-15T17:00:00-08:00')
* @param {string} calendarToken - Google Calendar API token
* @param {Array<string>} calendars - Array of calendar IDs to check (default: ['primary'])
* @returns {Promise<Object>} Free/busy information with busySlots, allFree flag, etc.
*/
async function getFreeBusy(timeMin, timeMax, calendarToken, calendars = ['primary']) {
if (!timeMin || !timeMax) {
throw new Error("Time range (timeMin and timeMax) is required");
}
const body = {
timeMin: timeMin,
timeMax: timeMax,
items: calendars.map(id => ({ id }))
};
const res = await fetch(
"https://www.googleapis.com/calendar/v3/freeBusy",
{
method: "POST",
headers: {
"Authorization": `Bearer ${calendarToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
}
);
if (!res.ok) {
const errorText = await res.text();
throw new Error(`Google Calendar API failed (${res.status}): ${errorText}`);
}
const data = await res.json();
// Process and simplify the response
const calendarStatus = {};
for (const calId of calendars) {
const calData = data.calendars[calId];
if (calData) {
calendarStatus[calId] = {
busySlots: calData.busy || [],
busyCount: (calData.busy || []).length,
errors: calData.errors || []
};
}
}
// Determine if entire range is free for all calendars
const allFree = Object.values(calendarStatus).every(cal => cal.busyCount === 0);
return {
timeMin,
timeMax,
calendars: calendarStatus,
allFree,
queriedAt: new Date().toISOString()
};
}
export { getFreeBusy };