# Nylas for scheduling and booking

Source: https://developer.nylas.com/docs/cookbook/use-cases/industries/scheduling/

Scheduling sits at the intersection of two messy data sources: calendars that live in any provider, and human availability that changes by the hour. A booking product has to read free and busy time from Google one moment and Microsoft 365 the next, then turn that into a clean grid of open slots a customer can click. The Calendar and Scheduler APIs absorb that cross-provider work behind one schema, so you write the booking logic once instead of maintaining a separate integration per provider.

Picking the wrong layer early is what makes a scheduling integration hard to unwind later, so the decisions come before the code: which products to combine for a Calendly-style experience, when to reach for the hosted Scheduler versus the raw availability API, and the provider quirks that decide how reliable a booking flow feels. The linked tutorials carry the step-by-step builds.

## Find open times across providers

Finding open times means reconciling several attendees' calendars into a single set of mutually free slots, even when those attendees use different providers. The platform exposes two endpoints for this. `POST /v3/calendars/availability` computes mutual free time across multiple attendees, and `POST /v3/grants/{grant_id}/calendars/free-busy` returns busy blocks for one person. Availability covers 4 providers, Google, Microsoft 365, iCloud, and Exchange, so a meeting between a Gmail host and a Microsoft 365 guest resolves correctly.

Use the availability endpoint when you're proposing meeting times to a group and want the API to do the intersection math for you. It takes the attendee list, the meeting duration, and a time window, and returns ranked open slots. The request below asks for shared availability across attendees and is the same call a booking page makes when it renders its slot grid.

```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": []
				}
			]
		}
	}'

```

Reach for Free/Busy instead when you only need one person's calendar and plan to apply your own slot logic on top. It's lighter, and it's the right tool when your product already knows the host and just needs their busy blocks to subtract from a working-hours template. This call returns busy intervals for a single grant over a time range.

```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"]
	}'

```

The split matters because the two endpoints have different provider coverage. Free/Busy supports the same set as availability except iCloud, and both exclude standard IMAP accounts, which carry no calendar data. If your audience includes iCloud users, route multi-attendee checks through the availability endpoint rather than stitching Free/Busy calls together yourself.

## Build a booking page with hosted Scheduler or the availability API

A booking page is the public surface where a customer picks a time, and you have two ways to build one. The hosted Scheduler renders the slot grid, timezone handling, and confirmation UI for you, while the raw availability API gives you the open slots as data so you can render your own front end. Both paths resolve slots across the 4 providers the availability endpoint supports, Google, Microsoft 365, iCloud, and Exchange, so the choice is about UI ownership, not provider reach. Most teams ship faster with the hosted path, then move to the raw API only when brand or workflow demands a custom UI.

Choose the hosted Scheduler when you want a working booking page with minimal front-end work. You create a configuration that defines the host, duration, and availability rules, then publish a page customers visit. Choose the raw availability API when you're embedding scheduling inside an existing product and the booking step needs to match your own design system or carry custom fields. In that case you call `POST /v3/calendars/availability` directly and build the grid in your app.

There's a hidden cost to the raw path worth naming up front. When you own the front end, you also own timezone rendering, double-booking guards, and the confirmation step, all of which the hosted Scheduler handles for you. That's fine when you have a design system and a reason to match it, but it adds work that doesn't differentiate your product. A useful rule of thumb: start hosted to validate the flow, and only rebuild the UI once you've confirmed customers actually book through it. The availability endpoint stays the same in both cases, so moving from hosted to custom later doesn't change how you compute open times.

The tutorials in this table walk through both directions, including a booking experience that records and transcribes every meeting and a multi-step interview pipeline with calendar holds. They show how the Scheduler combines with Notetaker and Calendar so you can see which products belong together before you commit to an architecture.

| Tutorial                                                                                                          | Products                       | What you'll build                                                                |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------ | -------------------------------------------------------------------------------- |
| [Add a scheduling page with automatic notetaking](/docs/cookbook/use-cases/build/scheduling-with-notetaking/)     | Scheduler, Notetaker           | A booking experience that automatically records and transcribes every meeting    |
| [Schedule reminders from calendar events](/docs/cookbook/use-cases/act/schedule-event-reminders/)                 | Calendar, Email                | A reminder system that sends email notifications before upcoming events          |
| [Build an interview scheduling pipeline](/docs/cookbook/use-cases/build/interview-scheduling-pipeline/)           | Scheduler, Calendar, Notetaker | A multi-step scheduling workflow with calendar holds and automatic transcription |

## Create and confirm bookings

A booking turns a chosen slot into a real calendar event on the host's calendar and, usually, a confirmation back to the attendee. With the hosted Scheduler, you create sessions through `POST /v3/scheduling/sessions` and manage the resulting bookings through the Scheduler endpoints. If you built the slot grid yourself, you write the event directly with `POST /v3/grants/{grant_id}/events`, which lands the meeting on the connected calendar across all 4 providers.

The difference is who owns the booking record. The Scheduler keeps a booking object you can list and confirm, which is handy when you want a pending state before the meeting becomes firm. Writing an event yourself skips that intermediate state and is simpler when the slot click should immediately create a confirmed meeting. The example below creates an event on a grant's calendar, the same operation a custom booking flow runs after a customer picks a time.

```bash
curl --compressed --request POST \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=<CALENDAR_ID>' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "Annual Philosophy Club Meeting",
    "busy": true,
    "conferencing": {
        "provider": "Zoom Meeting",
        "autocreate": {
          "conf_grant_id": "<NYLAS_GRANT_ID>",
          "conf_settings": {
            "settings": {
              "join_before_host": true,
              "waiting_room": false,
              "mute_upon_entry": false,
              "auto_recording": "none"
            }
          }
        }
      },
    "participants": [
      {
        "name": "Leyah Miller",
        "email": "leyah@example.com"
      },
      {
        "name": "Nyla",
        "email": "nyla@example.com"
      }
    ],
    "resources": [{
      "name": "Conference room",
      "email": "conference-room@example.com"
    }],
    "description": "Come ready to talk philosophy!",
    "when": {
      "start_time": 1674604800,
      "end_time": 1722382420,
      "start_timezone": "America/New_York",
      "end_timezone": "America/New_York"
    },
    "location": "New York Public Library, Cave room",
    "recurrence": [
      "RRULE:FREQ=WEEKLY;BYDAY=MO",
      "EXDATE:20211011T000000Z"
  ],
}'

```

One detail to plan for: a confirmed booking is a real event on a real calendar, so it inherits that provider's behavior for invites and notifications. When you write the event yourself, the attendee gets the provider's native calendar invite rather than a Scheduler confirmation, which can look different from what a hosted booking sends. Decide early whether your product should send its own branded confirmation email on top, because that choice affects how customers recognize the booking in their inbox.

From the terminal, the Scheduler exposes booking management without code. You can show a booking and confirm a specific one, which is useful for testing a flow or building an internal ops tool.

```bash
nylas scheduler bookings show <booking-id>
nylas scheduler bookings confirm <booking-id>
```

## Reschedule without back-and-forth

Rescheduling is the moment a booking product earns its keep, because moving a meeting normally means a chain of email. The Scheduler handles it through `nylas scheduler bookings reschedule`, which takes the booking ID plus the new `--start-time` and `--end-time`, moves an existing booking to a new time, and reissues the confirmation. That single command replaces the typical "does Thursday work instead?" thread, and it keeps the calendar event and the booking record in sync so neither side drifts.

Internally, a reschedule re-runs the same availability check that created the booking, so it respects the host's current free and busy state across the 4 supported providers. If you built a custom flow, you reschedule by recomputing availability with `POST /v3/calendars/availability` and updating the event. The terminal commands below cover the common Scheduler operations, from confirming to moving a booking.

```bash
nylas scheduler bookings show <booking-id>
nylas scheduler bookings confirm <booking-id>
nylas scheduler bookings reschedule <booking-id> --start-time <unix> --end-time <unix>
nylas scheduler configurations list
```

AI agents take rescheduling one step further by reading the request in plain language and proposing a new slot on their own. The tutorials in this table show agents that own scheduling end to end, including one with its own mailbox that books on your behalf and voice agents that turn "book me 30 minutes with Ada next Tuesday" into a real calendar hold.

| Tutorial                                                                                                              | Products                  | What you'll build                                                                            |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------- |
| [Scheduling agent with a dedicated identity](/docs/cookbook/use-cases/act/scheduling-agent-with-dedicated-identity/) | Agent Accounts, Scheduler | An agent with its own mailbox that books meetings on your behalf                              |
| [Connect voice agents to email & calendar](/docs/cookbook/cli/connect-voice-agents/)                                  | Calendar, Email           | Bridge LiveKit / Vapi / Retell to scheduling tools — "book me 30 min with Ada next Tuesday"  |
| [Build an LLM agent with email & calendar tools](/docs/cookbook/cli/llm-agent-with-tools/)                            | Email, Calendar           | Custom agent that reads incoming mail and proposes calendar slots                             |

## Run scheduling from the terminal with the Nylas CLI

The CLI gives you scheduling operations without writing a service, which makes it the fastest way to prototype a booking flow or run scheduling from a script. It mirrors the Calendar and Scheduler APIs, and the scheduling-relevant commands cover finding times across the 4 supported providers, listing configurations, and managing bookings. Start by finding a meeting time, then move into the Scheduler commands once a slot is chosen.

The find-time command is the terminal version of cross-provider availability. It ranks open slots on a 100-point model: working hours 40, time quality 25, cultural norms 15, weekday 10, and holiday avoidance 10. By default it looks for a 1 hour meeting over the next 7 days, so you only need to pass participants to get a ranked list back.

```bash
nylas calendar find-time --participants alice@example.com,bob@example.com --duration 1h --days 7
nylas calendar availability check
nylas calendar schedule ai "30 minutes with the design team next week"
```

Once you have a time, the Scheduler commands manage the booking lifecycle. You can list and create configurations, inspect a booking, and confirm or move it, all without leaving the shell. Adding `--json` to most commands returns structured output you can pipe into other tools.

```bash
nylas scheduler configurations list
nylas scheduler configurations create
nylas scheduler bookings show <booking-id>
nylas scheduler bookings confirm <booking-id>
nylas calendar events create --title "Intro call" --start <iso> --end <iso>
```

The CLI reads the same grants and calendars your application does, so anything you confirm in the terminal shows up in your product immediately. That shared state makes it a practical debugging surface when a booking lands in the wrong place or a slot grid looks off.

## Things to know about scheduling integrations

Scheduling integrations succeed or fail on provider details, so it pays to know the coverage map before you design the booking flow. The single most important fact is that availability covers 4 providers, Google, Microsoft 365, iCloud, and Exchange, behind one schema, but the two availability endpoints don't have identical reach. Free/Busy supports the same set except iCloud, and both endpoints exclude standard IMAP accounts because IMAP carries email only and exposes no calendar data.

That coverage gap drives a concrete design rule. If your customer base includes iCloud users and you need multi-attendee checks, route everything through `POST /v3/calendars/availability` rather than composing Free/Busy calls, because Free/Busy skips iCloud attendees. For IMAP users, treat scheduling as unavailable and fall back to a manual flow, since there's no calendar to read or write against.

Tokens are the next thing to get right. OAuth access tokens expire after 3,600 seconds, and the platform refreshes them automatically, so you don't write token-refresh code as long as you store the grant and let the API manage the lifecycle. A booking page that sits open for an hour still works on the next click because the refresh happens behind the request, which removes a class of "session expired" bugs that plague hand-rolled OAuth.

Timezone handling deserves explicit attention because a slot is only correct relative to a zone. The availability endpoint works in a defined time window, and your booking UI has to render those slots in the attendee's local zone, not the host's. Get this wrong and customers book the right hour in the wrong zone. Pin the timezone at the booking step, store it with the event, and confirm it in the confirmation message so both sides see the same local time.

Finally, the find-time scoring model is opinionated on purpose. Its 100-point ranking weights working hours at 40 and time quality at 25, which means it actively avoids late-night and lunch-hour slots even when calendars are technically free. That's usually what you want for human-facing booking, but if you're scheduling machine-to-machine jobs, the cultural-norm and weekday weights may push slots in directions a server doesn't care about. Know the weights so you can decide whether the default ranking fits your use case.

## What's next

- [Scheduler overview](/docs/v3/scheduler/): embeddable scheduling UI and API
- [Calendar availability](/docs/v3/calendar/calendar-availability/): check real-time availability
- [Hosted scheduling pages](/docs/v3/scheduler/hosted-scheduling-pages/): Nylas-hosted booking pages
- [Booking flows](/docs/v3/scheduler/customize-booking-flows/): customize the booking experience
- [Calendar API reference](/docs/v3/calendar/): events, availability, and Free/Busy endpoints
- [Post availability reference](/docs/reference/api/calendar/post-availability/): request and response schema for cross-provider slots
- [Nylas CLI command reference](https://cli.nylas.com/docs/commands): every `nylas calendar` and `nylas scheduler` command