# Find open meeting times across calendars

Source: https://developer.nylas.com/docs/cookbook/calendar/find-meeting-times/

You want to show open meeting times on a booking page, or pick a slot that works for three attendees on Google, Outlook, and iCloud. Doing it by hand means pulling each calendar, normalizing time zones, intersecting the free blocks, and re-running it every time a calendar changes. It's fiddly, and it breaks the moment someone's provider returns busy data in a different shape.

The Nylas availability API does the intersection for you. You send the participants and a time window, and it returns the slots when everyone is free, across every connected provider, in one response.

## How do I find times when everyone is free?

Send a `POST /v3/calendars/availability` request with the `participants`, a `start_time`/`end_time` window, and the meeting `duration_minutes`. Nylas reads each participant's calendar, intersects their busy times, and returns only the slots when all of them are free. It works across providers, so a meeting between Google, Outlook, and iCloud attendees comes back in one unified list.

The request below finds slots of 30 minutes for two participants within a time window. The `interval_minutes` field controls how finely the window is divided.

```bash
curl --compressed --request POST \
	--url 'https://api.us.nylas.com/v3/calendars/availability' \
	--header 'Accept: application/json' \
	--header 'Authorization: Bearer <NYLAS_API_KEY>' \
	--header 'Content-Type: application/json' \
	--data '{
		"participants": [
			{
				"email": "leyah@example.com",
				"calendar_ids": ["leyah@example.com"],
				"open_hours": [{
					"days": [0,1,2],
					"timezone": "America/Toronto",
					"start": "9:00",
					"end": "17:00",
					"exdates": []
				}]
			},
			{
				"email": "nyla@example.com",
			}
		],
		"start_time": 1600890600,
		"end_time": 1600999200,
		"interval_minutes": 30,
		"duration_minutes": 30,
		"round_to": 15,
		"availability_rules": {
			"availability_method": "collective",
			"buffer": {
				"before": 15,
				"after": 15
			},
			"default_open_hours": [
				{
					"days": [0,1,2],
					"timezone": "America/Toronto",
					"start": "9:00",
					"end": "17:00",
					"exdates": []
				},
				{
					"days": [3,4,5],
					"timezone": "America/Toronto",
					"start": "10:00",
					"end": "18:00",
					"exdates": []
				}
			]
		}
	}'

```

```js [getAvailability-Node.js]

import Nylas from "nylas";

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

const email = "<EMAIL>";

async function getCalendarAvailability() {
  try {
    const calendar = await nylas.calendars.getAvailability({
      requestBody: {
        startTime: 1630435200,
        endTime: 1630521600,
        durationMinutes: 15,
        participants: [{ email }],
      },
    });

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

getCalendarAvailability();


```

```python
from nylas import Client

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

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

availability = nylas.calendars.get_availability(
  request_body={
    "start_time": 1630435200,
    "end_time": 1630521600,
    "duration_minutes": 15,
    "participants": [{"email": email}]
  }
)

print(availability)

```

## How do I check one person's Free/Busy?

When you only need one user's schedule, `POST /v3/grants/{grant_id}/calendars/free-busy` is the lighter call. It skips slot generation and returns the raw busy blocks for the addresses you list. The body needs just 3 fields: `start_time`, `end_time`, and `emails`. An optional `tentative_as_busy` flag counts tentative events as busy. Use it to render a single calendar's busy ranges or to build your own slot logic.

The request below returns busy periods for one address over a time 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"]
	}'

```

```python
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)

```

## Find meeting times from the terminal

The [Nylas CLI](https://cli.nylas.com/docs/commands) finds the best meeting times directly: `nylas calendar find-time` takes a participant list and a duration, then returns slots ranked on a 100-point model rather than any free window. It defaults to a 1 hour meeting across the next 7 days.

```bash
nylas calendar find-time \
  --participants alice@example.com,bob@example.com \
  --duration 1h \
  --days 7
```

The score weighs working hours (40 points), time quality (25), cultural norms (15), weekday (10), and holiday avoidance (10). Tune the window with `--working-start`, `--working-end`, and `--timezones`. See the [`calendar find-time`](https://cli.nylas.com/docs/commands/calendar-find-time) command reference for every flag.

## How do I control which slots are returned?

The `availability_rules` and per-participant settings shape the results. Set `duration_minutes` for the meeting length and `interval_minutes` for how often a candidate slot starts, then add a `buffer` of, for example, 15 minutes before and after so back-to-back meetings don't get suggested. `round_to` snaps slot start times to a clean boundary.

For multi-host scheduling, `availability_method` decides how Nylas treats the hosts: `collective` finds times when every host is free, while the round-robin methods distribute meetings across hosts. Per-participant `open_hours` further restrict a person to their working hours and time zone. The [availability API reference](/docs/reference/api/calendar/post-availability/) documents every field.

## Things to know about availability

A few constraints are worth planning for. The availability endpoint covers 4 providers (Google, Microsoft, iCloud, and Exchange), while Free/Busy covers the same set except iCloud, which doesn't expose provider-side Free/Busy data. Both exclude standard IMAP accounts, which have no calendar to read. Every participant's calendar must be reachable, so a participant whose grant has expired skews the results toward "busy" or drops them from the calculation.

If you'd rather not build the booking UI yourself, the Nylas Scheduler wraps this same availability engine in a hosted page and UI components you embed. Reach for the raw API when you need a custom interface, and [Scheduler](/docs/v3/scheduler/) when you want the UI handled.

## What's next

- [Availability API reference](/docs/reference/api/calendar/post-availability/) for every request field
- [Check Free/Busy](/docs/v3/calendar/check-free-busy/) for the Free/Busy endpoint details
- [Create Google events](/docs/cookbook/calendar/events/create-events-google/) to book the slot once a time is chosen
- [Scheduler](/docs/v3/scheduler/) for a hosted booking experience on top of the same engine