Skip to content

How to add a Google Meet, Teams or Zoom link to a calendar event with an API

Updated

TL;DR

For Google Meet, send conferenceData.createRequest with a new requestId and conferenceSolutionKey.type set to hangoutsMeet, and add conferenceDataVersion=1 to the URL, or Google ignores the request. For Teams, set isOnlineMeeting: true and onlineMeetingProvider: "teamsForBusiness" on a Microsoft 365 calendar whose allowedOnlineMeetingProviders includes it; personal Outlook.com calendars don't. For Zoom, create the meeting with POST /v2/users/me/meetings and copy its join_url onto the event, within Zoom's limit of 100 creates or updates per user per day.

Google Meet

Google creates the Meet conference for you when you ask for one in the event body.

Create an event with a Meet linkHTTP
POST https://www.googleapis.com/calendar/v3/calendars/primary/events?conferenceDataVersion=1
Content-Type: application/json

{
  "summary": "Design review",
  "start": { "dateTime": "2026-11-03T10:00:00-05:00" },
  "end": { "dateTime": "2026-11-03T10:30:00-05:00" },
  "conferenceData": {
    "createRequest": {
      "requestId": "7f3c9a52-2b1e-4d8f-9c61-0e5a4b7d2f10",
      "conferenceSolutionKey": { "type": "hangoutsMeet" }
    }
  }
}

Forgetting conferenceDataVersion=1

This is the most common reason the event is created and the link is not. The events.insert reference says: "Version 0 assumes no conference data support and ignores conference data in the event's body." And: "The default is 0." Google returns 200, the event exists, and conferenceData is silently dropped. Google's create events guide puts it as a requirement: "To allow creation and modification of conference details, set the conferenceDataVersion request parameter to 1."

The requestId must be new for each conference you want created. Any random string works, and a UUID is the usual choice.

The pending status

Conferences are created asynchronously. Google's guide warns that "The immediate response to this call might not yet contain the fully-populated conferenceData", and the request carries a status of pending. The status values are pending, success and failure. If your response shows pending, read the event again before showing a link to anyone, and handle failure as a real outcome.

Key types

hangoutsMeet is the one to use. eventHangout and eventNamedHangout are deprecated, and addOn is for conferencing add-ons installed in Google Calendar, per the events.insert reference.

Updates that drop the conference

Google's guide warns that a client that mishandles conference data "may inadvertently remove existing conferences from users' events." In practice, use events.patch when you change other fields and leave conferenceData out. If you send a full update with conferenceDataVersion=1, send back the conferenceData you read.

Microsoft Teams

On Microsoft 365, the Teams meeting is a property of the Outlook event. Microsoft's online meetings guide says to check the calendar first: "Look for the allowedOnlineMeetingProviders and defaultOnlineMeetingProvider properties to verify if an Outlook calendar supports any online meeting providers."

Check which providers the calendar allowsHTTP
GET https://graph.microsoft.com/v1.0/me/calendar?$select=allowedOnlineMeetingProviders,defaultOnlineMeetingProvider

If the list contains teamsForBusiness, create the event with it.

Create an event with a Teams linkHTTP
POST https://graph.microsoft.com/v1.0/me/events
Content-Type: application/json

{
  "subject": "Design review",
  "start": { "dateTime": "2026-11-03T10:00:00", "timeZone": "Eastern Standard Time" },
  "end": { "dateTime": "2026-11-03T10:30:00", "timeZone": "Eastern Standard Time" },
  "isOnlineMeeting": true,
  "onlineMeetingProvider": "teamsForBusiness"
}

Read joinUrl, not onlineMeetingUrl

The link is in onlineMeeting.joinUrl. Microsoft says: "Do not use the onlineMeetingUrl property of the event because onlineMeetingUrl will soon be deprecated."

You cannot undo it

From the same guide: "Once you enable a meeting online, Microsoft Graph sets the meeting information in onlineMeeting. Subsequently, you cannot change the onlineMeetingProvider property, nor set isOnlineMeeting to false to disable the meeting online." If a user switches an event from Teams to Zoom in your product, you are deleting and recreating the event, not editing it.

Retries create duplicates

A POST that times out may still have created the event. The event resource has a transactionId property for this: send the same value on the retry and Outlook avoids creating a second event.

Personal Outlook.com accounts

The provider values are unknown, teamsForBusiness, skypeForBusiness and skypeForConsumer. A personal Outlook.com calendar does not list teamsForBusiness, and when we asked for Teams on one anyway, Graph created the event without a meeting and without an error. Read the property and hide the Teams option when it isn't there, rather than sending the request and hoping.

Editing the description later

The join link lives in the event's body, and Graph replaces the body whole on update. Changing the description afterwards removes the Teams join details unless you put them back.

Work accounts bring a separate problem. Microsoft's default consent policy blocks users from approving calendar permissions themselves, so many organizations need an administrator to approve your app before anyone can connect. See Need admin approval for Outlook calendar apps.

Zoom

Zoom links are not a calendar feature. You create a meeting in Zoom, then write its link onto the calendar event yourself.

Create a Zoom meetingHTTP
POST https://api.zoom.us/v2/users/me/meetings
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "topic": "Design review",
  "type": 2,
  "start_time": "2026-11-03T15:00:00Z",
  "duration": 30,
  "timezone": "America/New_York"
}

The Meetings API says: "For user-level apps, pass the me value" as the user ID. type is 1 for instant, 2 for scheduled, 3 for recurring with no fixed time and 8 for recurring with a fixed time. The scopes are meeting:write (or meeting:write:admin), or the granular meeting:write:meeting.

The response carries join_url for attendees and start_url for the host. Put join_url in the event's location or description on Google or Outlook.

start_url expires

Zoom's reference says the start_url "expiration time is two hours." Don't store it in the calendar event or send it in an email. When the host needs it, read the meeting again.

100 creates or updates per user per day

Zoom's rate limits page sets "100 create/update requests per day (UTC) per user", resetting at 00:00 UTC. Past it you get HTTP 429 and "You have reached the maximum daily rate limit for this API." Updates count too, so an app that rewrites the Zoom meeting every time a calendar event changes can lock a busy host out of scheduling for the rest of the day. Only update Zoom when the time or topic actually changed.

Errors you will see

From the Meetings API reference:

  • 404 with code 1001, "User does not exist."
  • 400 with code 3161, "Your user account is not allowed meeting hosting and scheduling capabilities."

Server-to-Server OAuth

For an account-level integration, Server-to-Server OAuth uses grant_type=account_credentials. Tokens last one hour and there is no refresh token: request a new one when it expires.

Side by side

Google Meet Microsoft Teams Zoom
How conferenceData.createRequest isOnlineMeeting + onlineMeetingProvider Separate API call, then edit the event
Required flag conferenceDataVersion=1 Provider must be in allowedOnlineMeetingProviders Host's Zoom account connected
Where the link is conferenceData, once success onlineMeeting.joinUrl join_url you copy onto the event
Catch pending on the first response Can't be removed or changed; not on Outlook.com 100 creates/updates per user per day; start_url expires

How Pyas handles it

With Pyas, you add conferencing: { provider: 'meet' }, 'teams' or 'zoom' to pyas.events.create. For Zoom, the host's Zoom account must be connected; Pyas creates the Zoom meeting and puts the link on the event. A Teams request on an Outlook.com (personal) account is refused with an error that says why, instead of an event without a link. Microsoft work accounts can still need an administrator's approval under Microsoft's default consent policy, with Pyas Auth too.

Common questions

Either conferenceDataVersion=1 is missing from the URL, so Google ignored conferenceData, or the create request is still pending. Check the first; read the event again for the second.

No. Microsoft does not let you set isOnlineMeeting back to false or change the provider. Delete the event and create a new one.

Does Zoom's daily limit apply per app or per user?

Per user. The 100 requests a day cover all meetings that user hosts, and reset at 00:00 UTC.

Not as a conference you create from the API. Google's addOn conference type belongs to conferencing add-ons installed in Google Calendar. With the API alone, put join_url in the event's location or description.

Teams on a personal Microsoft account saves the event without a linkUpdating an Outlook event's description removes its Teams join linkHow to fix "Need admin approval" (AADSTS65001, AADSTS90094) for an Outlook calendar app