# How to check free/busy status

Source: https://developer.nylas.com/docs/cookbook/calendar/check-free-busy/

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](/docs/reference/api/calendar/post-calendars-free-busy/) 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.

## Check Free/Busy for one or more people

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.

```bash
curl --compressed --request POST \
	--url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/calendars/free-busy' \
	--header 'Accept: application/json' \
	--header 'Authorization: Bearer <NYLAS_API_KEY>' \
	--header 'Content-Type: application/json' \
	--data '{
		"start_time": 1682467200,
		"end_time": 1682550000,
		"emails": ["leyah@example.com"]
	}'

```

```js [checkFreeBusy-Node.js SDK]

import Nylas from "nylas";

const nylas = new Nylas({
  apiKey: "<NYLAS_API_KEY>",
  apiUri: "<NYLAS_API_URI>",
});

const email = "<EMAIL>";

async function getFreeBusyCalendarInfo() {
  try {
    const calendar = await nylas.calendars.getFreeBusy({
      identifier: "<NYLAS_GRANT_ID>",
      requestBody: {
        startTime: 1630435200,
        endTime: 1630521600,
        emails: [email],
      },
    });

    console.log("Calendar:", calendar);
  } catch (error) {
    console.error("Error to create calendar:", error);
  }
}

getFreeBusyCalendarInfo();


```

```python [checkFreeBusy-Python SDK]

from nylas import Client

nylas = Client(
    "<NYLAS_API_KEY>",
    "<NYLAS_API_URI>"
)

grant_id = "<NYLAS_GRANT_ID>"
email = "<EMAIL>"

free_busy = nylas.calendars.get_free_busy(
  grant_id,
  request_body={
    "start_time":1630435200,
    "end_time":1630521600,
    "emails":[email]
  }
)

print(free_busy)

```

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.

## Read the busy time blocks

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`:

```json
{
  "request_id": "dd3ec9a2-8f15-403d-b269-32b1f1beb9f5",
  "data": [
    {
      "email": "user1@example.com",
      "time_slots": [
        {
          "start_time": 1690898400,
          "end_time": 1690902000,
          "status": "busy",
          "object": "time_slot"
        },
        {
          "start_time": 1691064000,
          "end_time": 1691067600,
          "status": "busy",
          "object": "time_slot"
        }
      ],
      "object": "free_busy"
    },
    {
      "email": "user2@example.com",
      "error": "Unable to resolve e-mail address user2@example.com to an Active Directory object.",
      "object": "error"
    }
  ]
}
```

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.

## Check free/busy from the terminal

Free/busy is the raw busy-block data behind any scheduling feature, and the [Nylas CLI](https://cli.nylas.com/docs/commands) 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.

```bash
nylas calendar availability check \
  --emails alice@example.com \
  --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`](https://cli.nylas.com/docs/commands/calendar-availability-check) command reference for every flag.

## Free/Busy vs availability

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](/docs/cookbook/calendar/find-meeting-times/) 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/Busy | Availability |
| --- | --- | --- |
| Endpoint | `POST /calendars/free-busy` | `POST /calendars/availability` |
| Returns | Raw busy time blocks per email | Bookable open slots across all attendees |
| Duration input | No | Yes, you set meeting length |
| Slot math | You compute open time | API computes it for you |
| Best for | Custom scheduling logic | Drop-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](/docs/cookbook/calendar/find-meeting-times/) for that flow.

## Things to know about Free/Busy

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](/docs/v3/auth/), 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.

### Provider behavior and private events

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.

### Time ranges, time zones, and limits

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.

### Per-email error handling

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](https://learn.microsoft.com/en-us/graph/api/calendar-getschedule) documents the underlying permissions if you're debugging a Microsoft mailbox.

## What's next

- [Find open meeting times](/docs/cookbook/calendar/find-meeting-times/) to turn busy blocks into ready-to-book slots with the availability endpoint
- [Hosted scheduling pages](/docs/v3/scheduler/hosted-scheduling-pages/) to embed a booking flow without building the slot picker yourself
- [Calendar API overview](/docs/v3/calendar/) for events, calendars, and recurring meetings
- [Get Free/Busy schedule reference](/docs/reference/api/calendar/post-calendars-free-busy/) for the full request and response schema
- [API reference](/docs/reference/api/) for every endpoint and parameter