Skip to content
Skip to main content

How to check free/busy status

Last updated:

Before you book a meeting, you need to know who’s already busy. A Free/Busy lookup answers exactly that: for each person you ask about, it returns the time blocks that fill their calendar, without exposing event titles or attendees. It’s the raw data layer every scheduling feature sits on top of, and the Calendar API returns it in one request.

This recipe shows how to query Free/Busy for one or more people, read the busy blocks the API returns, and decide when to reach for the availability endpoint instead.

Send a POST request to /v3/grants/{grant_id}/calendars/free-busy with a JSON body containing start_time, end_time, and an emails array. Times are Unix timestamps in seconds, in Coordinated Universal Time (UTC). You can include up to 50 email addresses for Google and up to 20 for Microsoft in a single request.

The start_time and end_time define the window the API scans for busy blocks. The emails array lists every person you want to check, and they all have to use the same provider. The example below checks one mailbox over a 23 hour window.

The grant you authenticate with needs permission to view each address’s Free/Busy data, which the calendar provider controls. You can widen the window up to 3 months from start_time for Google and EWS, or 62 days for Microsoft Graph.

The response is a data array with one entry per email you asked about. A successful entry has object: "free_busy" and a time_slots array, where each slot carries start_time, end_time (both Unix seconds), and a status of busy. A failed entry has object: "error" and an error string. The endpoint always returns 200 OK, so check each entry yourself.

Here’s a response checking 2 mailboxes. The first one resolved and returned 2 busy blocks. The second one failed because the provider couldn’t match the address, so it carries an error instead of time_slots:

To find open time, invert the result: any gap inside your requested window that no time_slots entry covers is free for that person. When you check several people at once, a moment is bookable only if it’s free across every successful entry. Treat any entry with object: "error" as unknown rather than free, so you don’t book over a calendar you couldn’t read.

Free/busy is the raw busy-block data behind any scheduling feature, and the Nylas CLI reads it with nylas calendar availability check. The command returns when the people on --emails are busy across a range, without exposing event titles or attendees.

nylas calendar availability check \
--emails [email protected] \
--start "2026-06-23 09:00" \
--end "2026-06-27 17:00"

The same command underpins slot-finding: once you have the busy blocks, nylas calendar find-time turns them into ranked openings across the next 7 days. See the calendar availability check command reference for every flag.

Free/Busy and availability solve related but different problems. Free/Busy returns raw busy intervals and leaves the slot math to you. The availability endpoint does that math for you: you pass a meeting duration and constraints, and it returns ready-to-book open slots across every attendee. Pick Free/Busy for custom logic, availability for a quick meeting picker.

The two endpoints take similar inputs but return opposite shapes. The table below sums up when each one fits, with the key difference being who computes the open slots.

Free/BusyAvailability
EndpointPOST /calendars/free-busyPOST /calendars/availability
ReturnsRaw busy time blocks per emailBookable open slots across all attendees
Duration inputNoYes, you set meeting length
Slot mathYou compute open timeAPI computes it for you
Best forCustom scheduling logicDrop-in meeting picker

If you only need to render someone’s busy ranges in a UI, Free/Busy is the lighter call. The moment you’re matching a 30 minute meeting against 4 calendars at once, switch to availability so you don’t rebuild overlap math across every attendee. See Find open meeting times for that flow.

Free/Busy depends on connected grants and provider rules, so a few behaviors are worth knowing before you ship. The lookup only works for accounts connected through a grant, all addresses in one request must share a provider, and iCloud isn’t supported at all. Below are the details that trip people up most often.

How much detail you get back depends on the provider and the target calendar’s sharing settings. On Google, the calling grant has to be able to see the other person’s Free/Busy, which Calendar sharing controls. On Microsoft Graph, the same applies through mailbox permissions, and Microsoft caps its calculation at 1,000 entries per time slot for each address. Private events still report as busy, but their titles and details never appear in the response, so you can query a colleague’s calendar without leaking what they’re doing. Neither provider includes all-day room resource bookings in the result.

Every timestamp in both the request and the response is Unix seconds in UTC, so convert to the user’s local zone in your own code before display. The window you can scan depends on the provider: up to 3 months past start_time for Google and EWS, and up to 62 days for Microsoft Graph. Per request, you can include up to 50 email addresses for Google and 20 for Microsoft. Keep the window tight and the list short, since a 3 month scan across dozens of busy calendars returns far more slots than a single day.

Because the endpoint returns 200 OK even when individual entries fail, error handling lives inside the data array, not the HTTP status. Loop over every entry and branch on object: process time_slots when it’s free_busy, and surface or retry the error string when it’s error. One bad address, like a misspelled name or a calendar your grant can’t read, won’t fail the whole batch, so the other 19 results still come back. The exact error text comes straight from the provider, as in the earlier Active Directory resolution message. The Microsoft Graph get schedule reference documents the underlying permissions if you’re debugging a Microsoft mailbox.