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.
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."
GET https://graph.microsoft.com/v1.0/me/calendar?$select=allowedOnlineMeetingProviders,defaultOnlineMeetingProviderIf the list contains teamsForBusiness, create the event with it.
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.
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
Why does my Google event have no Meet link?
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.
Can I remove a Teams link from an event?
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.
Can I put a Zoom link in Google's conferenceData?
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.