# Add video conferencing to Agent Account events

Source: https://developer.nylas.com/docs/cookbook/agent-accounts/add-conferencing/

An Agent Account can send a meeting invite, but its hosted calendar has no Zoom, Google Meet, or Microsoft Teams account of its own. So where does the video link come from? From a grant you've already connected. You pass that grant's ID as `conf_grant_id`, and Nylas creates the meeting on that account and attaches the join link to the agent's event.

This recipe creates an Agent Account event with a Zoom link, switches it to Google Meet or Microsoft Teams, adds links to Scheduler bookings, and changes or removes the meeting afterward.

## How does conferencing work on an Agent Account?

Conferencing on an Agent Account works through a second grant. The event lives on the Agent Account's calendar, and the meeting lives on the grant named in `conferencing.autocreate.conf_grant_id`. Nylas supports 3 providers for this: `Zoom Meeting`, `Google Meet`, and `Microsoft Teams`. All 3 require a `conf_grant_id`.

The user behind the conferencing grant is the meeting host. They're the account that owns the Zoom meeting or the Meet or Teams link, and they can admit people from a waiting room or end the call. The Agent Account is the event organizer and sends the invitations, but it doesn't host the video call.

| Provider | `conf_grant_id` must be | Where the meeting is created |
| --- | --- | --- |
| `Zoom Meeting` | A [Zoom grant](/docs/provider-guides/zoom-meetings/) | A Zoom meeting on the host's Zoom account |
| `Google Meet` | A Google grant | A private event with no attendees on the host's primary Google calendar, which holds the Meet link |
| `Microsoft Teams` | A Microsoft grant with a Microsoft 365 subscription | An event with no attendees on the host's primary Microsoft calendar, which holds the Teams link |

For Meet and Teams, the host's calendar gets an extra event at the same time as the agent's event. Nylas creates it without attendees so participants don't receive a second invitation from the host.

## Before you begin

You need 2 grants in the same Nylas application:

- **An Agent Account** that organizes the event. See the [Agent Accounts quickstart](/docs/v3/getting-started/agent-accounts/) to provision one.
- **A conferencing grant** for the account that hosts the meeting. For Zoom, [create a Zoom connector and authenticate the host](/docs/provider-guides/zoom-meetings/). Your Zoom OAuth app needs the `meeting:write:meeting`, `meeting:update:meeting`, and `meeting:delete:meeting` scopes. For Meet or Teams, use a Google or Microsoft grant you've already connected.


> **Info:** 
> **New to Nylas?** Start with the [quickstart guide](/docs/v3/getting-started/) to set up your app and connect a test account before continuing here.


Nylas rejects a `conf_grant_id` from a different application, so both grants must belong to the application whose API key you use.

## Create an Agent Account event with a Zoom link

A [`POST /v3/grants/{grant_id}/events`](/docs/reference/api/events/create-event/) request with a `conferencing.autocreate` object creates the event and the Zoom meeting together. Nylas saves the event first, creates the meeting on the Zoom grant, and attaches the link before it sends invitations. The event needs a `title` and a `when` for the meeting to be created.

```bash
curl --request POST \
  --url "https://api.us.nylas.com/v3/grants/<AGENT_ACCOUNT_GRANT_ID>/events?calendar_id=primary&notify_participants=true" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "title": "Onboarding call",
    "when": { "start_time": 1790265600, "end_time": 1790269200 },
    "participants": [
      { "email": "jordan.lee@example.com" }
    ],
    "conferencing": {
      "provider": "Zoom Meeting",
      "autocreate": {
        "conf_grant_id": "<ZOOM_GRANT_ID>"
      }
    }
  }'
```

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


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

const event = await nylas.events.create({
  identifier: "<AGENT_ACCOUNT_GRANT_ID>",
  requestBody: {
    title: "Onboarding call",
    when: { startTime: 1790265600, endTime: 1790269200 },
    participants: [{ email: "jordan.lee@example.com" }],
    conferencing: {
      provider: "Zoom Meeting",
      autocreate: { conf_grant_id: "<ZOOM_GRANT_ID>" },
    },
  },
  queryParams: {
    calendarId: "primary",
    notifyParticipants: true,
  },
});

console.log(event.data.conferencing);
```

```python [agentConferencing-Python SDK]
from nylas import Client

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

event = nylas.events.create(
    "<AGENT_ACCOUNT_GRANT_ID>",
    request_body={
        "title": "Onboarding call",
        "when": {"start_time": 1790265600, "end_time": 1790269200},
        "participants": [{"email": "jordan.lee@example.com"}],
        "conferencing": {
            "provider": "Zoom Meeting",
            "autocreate": {"conf_grant_id": "<ZOOM_GRANT_ID>"},
        },
    },
    query_params={"calendar_id": "primary", "notify_participants": True},
)

print(event.data.conferencing)
```

The response returns the meeting in `conferencing.details`. For Zoom, that includes 3 fields: the join `url`, the `meeting_code`, and the `password`. The `conf_grant_id` isn't echoed back. If the event has no `location`, Nylas sets it to the join URL, and Nylas keeps any `location` you pass, like a room name.

```json [agentConferencingResponse-Response (JSON)]
{
  "request_id": "5fa64c92-e840-4357-86b9-2aa364d35b88",
  "data": {
    "id": "<EVENT_ID>",
    "grant_id": "<AGENT_ACCOUNT_GRANT_ID>",
    "calendar_id": "primary",
    "title": "Onboarding call",
    "location": "https://us06web.zoom.us/j/85230174962?pwd=<PASSWORD_HASH>",
    "conferencing": {
      "provider": "Zoom Meeting",
      "details": {
        "url": "https://us06web.zoom.us/j/85230174962?pwd=<PASSWORD_HASH>",
        "meeting_code": "85230174962",
        "password": "<PASSWORD>"
      }
    },
    "when": {
      "start_time": 1790265600,
      "end_time": 1790269200,
      "object": "timespan"
    },
    "object": "event"
  }
}
```

A [`GET /v3/grants/{grant_id}/events/{event_id}`](/docs/reference/api/events/get-events-id/) request returns the same `conferencing` object for the event afterward.

## Use Google Meet or Microsoft Teams instead

Switching providers takes 2 changes: set `provider` to `Google Meet` or `Microsoft Teams`, and set `conf_grant_id` to a Google or Microsoft grant. Everything else in the create request stays the same. Teams links need a Microsoft 365 subscription on the host account, the same requirement as [automatic conferencing on connected grants](/docs/v3/calendar/add-conferencing/).

```json
"conferencing": {
  "provider": "Google Meet",
  "autocreate": {
    "conf_grant_id": "<GOOGLE_GRANT_ID>"
  }
}
```

The Meet or Teams link comes from an event Nylas creates on the host's primary calendar. The host sees that event on their own calendar with no attendees. Leave it in place: Nylas removes it when you delete the Agent Account event or replace its conferencing.

## Add conferencing to Scheduler bookings

A Scheduler Configuration with an Agent Account organizer takes the same `conferencing` object under `event_booking`. Every booked event gets its own meeting, created with the `conf_grant_id` you set on the Configuration. That means every booking on the page is hosted by the same Zoom, Google, or Microsoft account.

```bash
curl --request PUT \
  --url "https://api.us.nylas.com/v3/grants/<AGENT_ACCOUNT_GRANT_ID>/scheduling/configurations/<CONFIGURATION_ID>" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "event_booking": {
      "title": "Support callback",
      "conferencing": {
        "provider": "Zoom Meeting",
        "autocreate": {
          "conf_grant_id": "<ZOOM_GRANT_ID>"
        }
      }
    }
  }'
```

If the meeting can't be created for a booking, Scheduler still books the slot without a link. See [Use Scheduler with Agent Accounts](/docs/v3/scheduler/agent-accounts/) for the remaining Configuration setup.

## Change or remove the meeting link

A [`PUT /v3/grants/{grant_id}/events/{event_id}`](/docs/reference/api/events/put-events-id/) request that leaves out `conferencing` keeps the existing meeting. When you include a `conferencing` object, Nylas replaces the meeting in 2 steps: it deletes the old meeting on the provider, then creates the new one. The request below replaces the Zoom meeting with a new one and notifies participants of the new link.

```bash
curl --request PUT \
  --url "https://api.us.nylas.com/v3/grants/<AGENT_ACCOUNT_GRANT_ID>/events/<EVENT_ID>?calendar_id=primary&notify_participants=true" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "conferencing": {
      "provider": "Zoom Meeting",
      "autocreate": {
        "conf_grant_id": "<ZOOM_GRANT_ID>"
      }
    }
  }'
```

To remove the meeting and keep the event, set `conferencing` to `{}`. Deleting the event with [`DELETE /v3/grants/{grant_id}/events/{event_id}`](/docs/reference/api/events/delete-events-id/) also deletes the meeting on the provider. If Nylas can't reach the provider to delete the meeting, the event delete fails and the event stays, so retry the request. That way, deleting an event never leaves a meeting behind that people can still join.

## Things to know about Agent Account conferencing

- **A failed meeting doesn't fail the event.** If the conferencing grant is expired, belongs to another application, or the provider rejects the request, the event is still created without a link and the API doesn't return an error. Check that `conferencing.details.url` is present in the response before you tell a participant the meeting has a link.
- **Rescheduling through the Events API doesn't update the meeting.** Changing the event's `when` or `title` with a `PUT` request doesn't change the Zoom meeting's scheduled time or topic. The join link keeps working. To create a new meeting that matches, send the `conferencing` object again in the same update.
- **One host per request.** A `conf_grant_id` names exactly 1 account, so every meeting created from a request or a Scheduler Configuration is hosted by that account. Round-robin pools can't create a meeting per host.
- **Zoom settings pass through.** `conf_settings` in the `autocreate` object sends its keys to Zoom's meeting create request. They work the same way as on connected grants, and Nylas doesn't validate them. Google Meet and Microsoft Teams ignore `conf_settings`. The [Create Event reference](/docs/reference/api/events/create-event/) documents the field.
- **Only 1 phone number is kept.** When a provider returns several dial-in numbers, the event stores the first one in `conferencing.details.phone`.
- **Recurring events share one meeting.** A recurring event gets 1 meeting for the whole series. Deleting a single occurrence doesn't delete the meeting, but deleting the series does.

## What's next

- [How Agent Account calendars work](/docs/v3/agent-accounts/calendars/) for hosting events, invitations, and RSVPs from an Agent Account
- [Use Scheduler with Agent Accounts](/docs/v3/scheduler/agent-accounts/) to give the agent a booking page
- [Authenticating Zoom Meetings accounts](/docs/provider-guides/zoom-meetings/) to create the Zoom connector and grant you pass as `conf_grant_id`
- [Adding conferencing to events](/docs/v3/calendar/add-conferencing/) for conferencing on connected Google and Microsoft grants
- [Add conferencing to calendar events](/docs/cookbook/calendar/add-conferencing/) for the same `autocreate` flow on connected Google and Microsoft grants
- [Scheduling agent with a dedicated identity](/docs/cookbook/use-cases/act/scheduling-agent-with-dedicated-identity/) for an end-to-end agent that books meetings from its own calendar
- [Events API reference](/docs/reference/api/events/) for the full `conferencing` request and response schemas