# How Agent Account calendars work

Source: https://developer.nylas.com/docs/v3/agent-accounts/calendars/

Every Agent Account ships with a real calendar. It hosts events that real people accept in Google Calendar, Microsoft 365, or Apple Calendar. It receives invitations from anyone who sends to its email address. It RSVPs back with `yes`, `no`, or `maybe`. From a participant's perspective, there's nothing special about it -- it's just another attendee on the invite.

This page covers how an Agent Account's calendar works across the two directions that matter: the agent as organizer, and the agent as invitee. For the complete endpoint list, see [Supported endpoints](/docs/v3/agent-accounts/supported-endpoints/).

## The calendar at a glance

When Nylas provisions an Agent Account, it creates a primary calendar that belongs to the account. You can list it, create additional calendars up to your plan's cap, and query free/busy -- all through the existing [Calendars](/docs/reference/api/calendar/) and [Events](/docs/reference/api/events/) endpoints at `/v3/grants/{grant_id}/...`.

- **A primary calendar**, provisioned automatically. It can't be deleted while other calendars exist on the account.
- **Additional calendars**, up to your plan's cap, created with [`POST /calendars`](/docs/reference/api/calendar/create-calendar/). Useful for separating concerns -- for example, a `sales-calls` calendar and an `internal` calendar on the same agent.
- **Free/busy queries** via [the free/busy endpoint](/docs/reference/api/calendar/post-calendars-free-busy/), which returns busy blocks over a time range. This is how an agent checks its own availability before proposing a meeting slot.
- **Event webhooks** -- [`event.created`](/docs/reference/notifications/events/event-created/), [`event.updated`](/docs/reference/notifications/events/event-updated/), and [`event.deleted`](/docs/reference/notifications/events/event-deleted/) fire for every change to an Agent Account's events, whether the change originated from the agent or from someone responding to an invitation.

## Hosting events

When the agent [creates an event](/docs/reference/api/events/create-event/) and passes `notify_participants=true`, an invitation goes out to each participant from the Agent Account's email address. The participant then experiences the same thing they'd see for an invite from a colleague:

- A Google Calendar user sees the invite in Gmail, clicks **Yes**, **No**, or **Maybe**, and Google Calendar sends the response back to the Agent Account's mailbox automatically.
- An Outlook user sees it in Outlook, clicks **Accept**, **Decline**, or **Tentative**, and Microsoft sends the response back the same way.
- An Apple Calendar user sees it in Mail, responds, and iCloud sends the reply back.

Each response lands in the Agent Account's mailbox, Nylas reads it, and the event's `participants[].status` is updated automatically. An [`event.updated`](/docs/reference/notifications/events/event-updated/) webhook fires so the agent knows who said yes without having to inspect the mailbox.

```bash
curl --request POST \
  --url "https://api.us.nylas.com/v3/grants/<GRANT_ID>/events?calendar_id=primary&notify_participants=true" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "title": "Product demo",
    "when": { "start_time": 1744387200, "end_time": 1744390800 },
    "participants": [
      { "email": "alice@example.com" },
      { "email": "bob@example.com" }
    ]
  }'
```

Updates and cancellations work the same way:

- [`PUT /events/{id}`](/docs/reference/api/events/put-events-id/) with changed fields updates the event on every participant's calendar -- the time, title, or location changes wherever they're looking at it.
- [`DELETE /events/{id}`](/docs/reference/api/events/delete-events-id/) removes the event from every participant's calendar.

Pass `notify_participants=false` on any of these when you want to make a change silently -- useful for pre-staging events the agent will announce later, or for backfilling historical data without notifying anyone.

## Receiving invitations

When someone invites the Agent Account to their meeting, the invitation moves through the mailbox and automatically shows up on the calendar:

1. A person in Google Calendar, Outlook, Apple Calendar, or another Agent Account creates an event and adds the Agent Account's address as a participant.
2. Their calendar sends the invitation to the Agent Account's mailbox. Nylas sees it, parses the meeting details, and creates a matching event on the Agent Account's primary calendar. [`event.created`](/docs/reference/notifications/events/event-created/) fires.
3. The event has the agent listed as a participant with `status: "noreply"`. The organizer is whoever sent the invite, not the Agent Account. The agent's RSVP is pending.

This means you can drive the agent's calendar logic off the `event.created` webhook without ever looking at the invite email -- the event object already has the organizer, participants, times, and description the agent needs to decide how to respond.

## Sending an RSVP

When the agent wants to respond to an invitation, use [`POST /events/{event_id}/send-rsvp`](/docs/reference/api/events/send-rsvp/) with `status: "yes"`, `"no"`, or `"maybe"`:

```bash
curl --request POST \
  --url "https://api.us.nylas.com/v3/grants/<GRANT_ID>/events/<EVENT_ID>/send-rsvp?calendar_id=primary" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{ "status": "yes" }'
```

From the organizer's perspective, the agent's response appears in their calendar the same way any attendee's response would -- the organizer sees the agent as "accepted" (or "declined", or "tentative") next to every other participant. Other attendees see it too, because their calendars get the update automatically.

The `send-rsvp` endpoint is the correct way for an Agent Account to respond to an invitation -- a plain reply email won't update the organizer's calendar. After the call, [`event.updated`](/docs/reference/notifications/events/event-updated/) fires on the Agent Account's own calendar so the agent sees its own state change.

### Proposing a different time

Counter-proposing a time isn't a first-class endpoint today. The common pattern is to RSVP with `no` or `maybe`, then reply to the invite email with a proposed alternative and let the organizer create a new event. For flows that need round-trip time negotiation -- proposing slots, collecting picks, booking the winner -- [Scheduler](/docs/v3/scheduler/) is purpose-built and works with Agent Accounts.

## Free/busy

[The free/busy endpoint](/docs/reference/api/calendar/post-calendars-free-busy/) returns busy blocks for the Agent Account's primary calendar over a time window. This is what you'd use when the agent needs to propose a meeting time before creating the event. See [Supported endpoints](/docs/v3/agent-accounts/supported-endpoints/#calendars) for the full list of calendar endpoints that work with Agent Account grants.

## Keep in mind

- **An Agent Account is always a real mailbox too.** The `event.created` webhook for an inbound invite fires alongside `message.created` for the invitation email itself. Decide which one drives the agent's logic and ignore the other.
- **Set `notify_participants` intentionally.** Every create, update, and delete with `notify_participants=true` sends email, and each of those invitations counts toward the Agent Account's [daily send quota](/docs/v3/agent-accounts/send-limits/#sending-limits). If the account is already over its quota, the event still saves but the invitation is skipped silently, so no one is notified. For bulk backfill or silent state changes, pass `false`.
- **Cancellations matter.** Deleting an event without `notify_participants=true` leaves the meeting on participants' calendars. Delete with notification unless you have a reason not to.
- **Times live on the event.** Pass `timezone` on create, or rely on epoch `start_time` / `end_time` -- the Agent Account itself doesn't have a default time zone the way a human user's calendar does.
- **Scheduler is the right tool for negotiation-heavy flows.** If the agent's job is to propose, agree, and book meetings across many participants, [Scheduler](/docs/v3/scheduler/) handles the round-trip. The Events API is for cases where the agent already knows the time and just needs to create or respond to invites.

## What's next

- [Agent Accounts quickstart](/docs/v3/getting-started/agent-accounts/) to create an account and exercise the Events API
- [Scheduling agent with a dedicated identity](/docs/cookbook/use-cases/act/scheduling-agent-with-dedicated-identity/) -- an end-to-end tutorial for an Agent Account that books meetings
- [Supported endpoints](/docs/v3/agent-accounts/supported-endpoints/) for the full list of Calendars and Events endpoints that work with Agent Account grants
- [Events API reference](/docs/reference/api/events/) for request and response schemas on create, update, delete, and send-rsvp
- [Using the Events API](/docs/v3/calendar/using-the-events-api/) for the general Calendar API surface these endpoints share with connected grants
- [Policies, Rules, and Lists](/docs/v3/agent-accounts/policies-rules-lists/) to filter invitation emails before they reach the agent's inbox