A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Google Calendar API is how an app or AI agent works with a person's calendars: reading and creating events, checking when people are free or busy, organizing the calendars a user follows, and managing who is allowed to see or change a calendar. Access is granted through OAuth, where the scopes a token carries decide which calendars it can reach and whether it can only read or also write. Google can push a notification to an app whenever a watched calendar changes, so it learns about activity without repeatedly asking.
How an app or AI agent connects to Google Calendar determines what it can reach. There is a route for making calls, a route for receiving change notifications, and a hosted server that exposes Calendar tools to agents, and each is governed by the OAuth grant behind it and the scopes that grant carries.
The Calendar API answers at https://www.googleapis.com under the /calendar/v3 path, taking JSON request bodies and returning JSON. A call authenticates with an OAuth 2.0 access token in the Authorization header, and lists page through a pageToken with an optional nextSyncToken for incremental sync.
A watch request on events, the calendar list, sharing rules, or settings opens a notification channel, and Google then POSTs to the channel's HTTPS address each time the resource changes. The notification says the resource changed rather than carrying the new data, so the app re-fetches. A channel is closed with channels.stop.
Google's hosted Calendar MCP server at https://calendarmcp.googleapis.com/mcp/v1 lets an agent call Calendar through the Model Context Protocol. It authenticates with OAuth 2.0 and exposes eight tools: create_event, delete_event, get_event, update_event, list_calendars, list_events, respond_to_event, and suggest_time. It is in the Google Workspace Developer Preview Program, not yet generally available.
A user signs in and consents to the requested scopes, and the app receives an access token that acts as that user and reaches only what those scopes allow. This is the standard way an app or AI agent connects to one person's calendars.
A service account is an app's own identity that calls the API without a person present, useful for backend automation. It can reach a calendar that has been shared with it, and in Google Workspace it can be granted domain-wide delegation to act as users across the organization.
A Google Workspace administrator authorizes a service account to impersonate users across the domain for chosen scopes, so the app can act as any user without each user consenting. It is a broad grant reserved for trusted backend integrations.
The Google Calendar API is split into areas an agent can act on, such as events, calendars, the user's calendar list, sharing rules, and free/busy lookups. Each area has its own methods and its own scopes, and some reach far more than others.
List, read, create, update, move, import, and delete events on a calendar, add an event from a line of text, and list the occurrences of a recurring event.
Read, create, update, and delete calendars themselves, clear a primary calendar, and transfer ownership of a secondary calendar.
List, read, add, update, and remove the calendars that appear in the user's own calendar list.
List, read, create, update, and delete the rules that say who can see or change a calendar.
Query when a set of calendars is busy or free over a time window, without reading the events themselves.
Read a user's Calendar settings, such as time zone, and read the global color palette for calendars and events.
Stop a push-notification channel that was opened by a watch request.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
EventsList, read, create, update, move, import, and delete events on a calendar, add an event from a line of text, and list the occurrences of a recurring event.11 | ||||||
| GET | /calendars/{calendarId}/events | List the events on a calendar, with filtering by time window, and incremental sync through a sync token. | read | calendar.events.readonly | Current | |
Reading needs one of the read scopes: https://www.googleapis.com/auth/calendar.events.readonly, calendar.events, calendar.readonly, or calendar. A nextSyncToken in the response lets a later call return only what changed. Acts onevent Permission (capability) calendar.events.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /calendars/{calendarId}/events/{eventId} | Get a single event by its id. | read | calendar.events.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events.readonly. The broader calendar.events, calendar.readonly, or calendar scope also works. Acts onevent Permission (capability) calendar.events.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/events | Create an event on a calendar, optionally with attendees, reminders, and a conference link. | write | calendar.events | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events. The broader calendar scope also works. Inviting attendees can send them email. Acts onevent Permission (capability) calendar.eventsVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /calendars/{calendarId}/events/{eventId} | Replace an event with a new version (full update). | write | calendar.events | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events. A full update overwrites unset fields, where patch changes only the fields sent. Acts onevent Permission (capability) calendar.eventsVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /calendars/{calendarId}/events/{eventId} | Update only the fields of an event that are sent (partial update). | write | calendar.events | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events. Patch is the safe way to change shared properties, since it leaves other fields untouched. Acts onevent Permission (capability) calendar.eventsVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /calendars/{calendarId}/events/{eventId} | Delete an event from a calendar. | write | calendar.events | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events. Deleting an event with attendees can notify them. Acts onevent Permission (capability) calendar.eventsVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/events/quickAdd | Create an event from a single line of text, such as 'Lunch with Sam on Friday at 1pm'. | write | calendar.events | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events. Google parses the text into a timed event. Acts onevent Permission (capability) calendar.eventsVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/events/{eventId}/move | Move an event from one calendar to another. | write | calendar.events | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events. Only single, non-recurring events can be moved between calendars. Acts onevent Permission (capability) calendar.eventsVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/events/import | Import an existing event into a calendar, keeping its original identifiers (used to copy an event without sending invitations). | write | calendar.events | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events. Unlike insert, import is for adding a private copy of an existing event, not creating a new invitation. Acts onevent Permission (capability) calendar.eventsVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /calendars/{calendarId}/events/{eventId}/instances | List the individual occurrences of a recurring event. | read | calendar.events.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events.readonly. Returns each dated instance of the recurring series. Acts onevent Permission (capability) calendar.events.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/events/watch | Open a push-notification channel that fires when events on the calendar change. | read | calendar.events.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.events.readonly. Watch needs the same read scope as listing events. The notification says the resource changed; the app then re-fetches. Acts onevent Permission (capability) calendar.events.readonlyVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
CalendarsRead, create, update, and delete calendars themselves, clear a primary calendar, and transfer ownership of a secondary calendar.6 | ||||||
| GET | /calendars/{calendarId} | Get the metadata of a calendar, such as its summary and time zone. | read | calendar.calendars.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.calendars.readonly. The broader calendar.readonly or calendar scope also works. Acts oncalendar Permission (capability) calendar.calendars.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars | Create a new secondary calendar. | write | calendar.calendars | Current | |
Authorized scopes: https://www.googleapis.com/auth/calendar.calendars, calendar, or calendar.app.created. Acts oncalendar Permission (capability) calendar.calendarsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /calendars/{calendarId} | Update a calendar's metadata, such as its name or time zone. | write | calendar.calendars | Current | |
Authorized scopes: https://www.googleapis.com/auth/calendar.calendars or calendar. Acts oncalendar Permission (capability) calendar.calendarsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /calendars/{calendarId} | Delete a secondary calendar, removing it and all its events. | write | calendar.calendars | Current | |
Authorized scopes: https://www.googleapis.com/auth/calendar.calendars or calendar. The primary calendar cannot be deleted; use clear instead. Acts oncalendar Permission (capability) calendar.calendarsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/clear | Delete every event from a user's primary calendar. | write | calendar | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar. Clear empties the primary calendar of all its events at once. Acts oncalendar Permission (capability) calendarVersionAvailable since the API’s base version Webhook event events-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/transferOwnership | Transfer ownership of a secondary calendar to another user in the same organization. | write | calendar.calendars | New | |
Authorized scopes: https://www.googleapis.com/auth/calendar or calendar.calendars. Requires the Manage Calendars administrator privilege. Added 18 June 2026. Acts oncalendar Permission (capability) calendar.calendarsVersionIntroduced 2026-06-18 Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Calendar listList, read, add, update, and remove the calendars that appear in the user's own calendar list.5 | ||||||
| GET | /users/me/calendarList | List the calendars in the user's own calendar list. | read | calendar.calendarlist.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.calendarlist.readonly. The calendar list is the set of calendars a user has added to their own view, separate from the calendars themselves. Acts oncalendar list entry Permission (capability) calendar.calendarlist.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /users/me/calendarList/{calendarId} | Get one entry from the user's calendar list. | read | calendar.calendarlist.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.calendarlist.readonly. The broader calendar.readonly or calendar scope also works. Acts oncalendar list entry Permission (capability) calendar.calendarlist.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /users/me/calendarList | Add an existing calendar to the user's calendar list. | write | calendar.calendarlist | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.calendarlist. Adding to the list does not create a calendar; it subscribes the user to one that already exists. Acts oncalendar list entry Permission (capability) calendar.calendarlistVersionAvailable since the API’s base version Webhook event calendarlist-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /users/me/calendarList/{calendarId} | Update an entry in the user's calendar list, such as its color or notification settings. | write | calendar.calendarlist | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.calendarlist. Acts oncalendar list entry Permission (capability) calendar.calendarlistVersionAvailable since the API’s base version Webhook event calendarlist-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /users/me/calendarList/{calendarId} | Remove a calendar from the user's calendar list. | write | calendar.calendarlist | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.calendarlist. Removing the entry unsubscribes the user but does not delete the underlying calendar. Acts oncalendar list entry Permission (capability) calendar.calendarlistVersionAvailable since the API’s base version Webhook event calendarlist-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Sharing rules (Acl)List, read, create, update, and delete the rules that say who can see or change a calendar.4 | ||||||
| GET | /calendars/{calendarId}/acl | List the access-control rules on a calendar, which say who can see or change it. | read | calendar.acls.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.acls.readonly. The broader calendar.acls or calendar scope also works. Each rule grants a person, group, or domain one of none, freeBusyReader, reader, writer, or owner. Acts onacl rule Permission (capability) calendar.acls.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /calendars/{calendarId}/acl/{ruleId} | Get a single access-control rule on a calendar. | read | calendar.acls.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.acls.readonly. Acts onacl rule Permission (capability) calendar.acls.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /calendars/{calendarId}/acl | Create an access-control rule, sharing a calendar with a person, group, or domain. | write | calendar.acls | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.acls. The broader calendar scope also works. A writer or owner rule grants edit access to the whole calendar. Acts onacl rule Permission (capability) calendar.aclsVersionAvailable since the API’s base version Webhook event acl-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /calendars/{calendarId}/acl/{ruleId} | Delete an access-control rule, removing someone's access to a calendar. | write | calendar.acls | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.acls. Acts onacl rule Permission (capability) calendar.aclsVersionAvailable since the API’s base version Webhook event acl-changedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Free/busyQuery when a set of calendars is busy or free over a time window, without reading the events themselves.1 | ||||||
| POST | /freeBusy | Return free/busy information for a set of calendars over a time window. | read | calendar.events.freebusy | Current | |
Least-privilege scope: https://www.googleapis.com/auth/calendar.events.freebusy. The broader calendar.readonly or calendar scope also works. It returns busy blocks only, not event titles or details. Acts onfree/busy response Permission (capability) calendar.events.freebusyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Settings & colorsRead a user's Calendar settings, such as time zone, and read the global color palette for calendars and events.3 | ||||||
| GET | /users/me/settings | List a user's Calendar settings, such as time zone and date format. | read | calendar.settings.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.settings.readonly. The broader calendar.readonly or calendar scope also works. Acts onsetting Permission (capability) calendar.settings.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /users/me/settings/{setting} | Get one of a user's Calendar settings by id. | read | calendar.settings.readonly | Current | |
Full scope URL: https://www.googleapis.com/auth/calendar.settings.readonly. Acts onsetting Permission (capability) calendar.settings.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /colors | Get the global palette of color definitions for calendars and events. | read | calendar.readonly | Current | |
Authorized scopes: https://www.googleapis.com/auth/calendar.readonly or calendar. The palette is read-only and referenced by the colorId on calendars and events. Acts oncolor palette Permission (capability) calendar.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Notification channelsStop a push-notification channel that was opened by a watch request.1 | ||||||
| POST | /channels/stop | Stop a push-notification channel opened by a watch request, so notifications stop arriving. | write | calendar.events.readonly | Current | |
Needs a scope that can read the watched resource, such as https://www.googleapis.com/auth/calendar.events.readonly. The request carries the channel id and resourceId returned when the channel was opened. Acts onchannel Permission (capability) calendar.events.readonlyVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Google Calendar can notify an app or AI agent when a watched resource changes, instead of the app repeatedly asking. A watch request opens a notification channel, and Google then posts a message to the channel's HTTPS address each time the resource changes.
| Event | What it signals | Triggered by |
|---|---|---|
Events changed | Fires when an event on a watched calendar is created, updated, moved, imported, or deleted. The notification reports that the events collection changed; the app re-lists with its sync token to learn what changed. | /calendars/{calendarId}/events/calendars/{calendarId}/events/{eventId}/calendars/{calendarId}/events/{eventId}/calendars/{calendarId}/events/{eventId}/calendars/{calendarId}/events/quickAdd/calendars/{calendarId}/events/{eventId}/move/calendars/{calendarId}/events/import/calendars/{calendarId}/events/watch/calendars/{calendarId}/clear |
Calendar list changed | Fires when the user's calendar list changes, such as a calendar being added, updated, or removed from their view. | /users/me/calendarList/users/me/calendarList/{calendarId}/users/me/calendarList/{calendarId} |
Sharing rules changed | Fires when a calendar's access-control rules change, such as a sharing rule being added or removed. | /calendars/{calendarId}/acl/calendars/{calendarId}/acl/{ruleId} |
Google Calendar limits how fast an app or AI agent can call, through a sliding per-minute quota counted per project and per user, with a separate much larger daily ceiling per project.
Google Calendar meters requests by a sliding per-minute quota rather than a per-method cost. A project gets 10,000 requests per minute, and each user within a project gets 600 requests per minute, with a separate daily ceiling of 1,000,000 requests per project. Going over returns 403 with rateLimitExceeded or userRateLimitExceeded, or 429 when too many requests arrive at once. The guidance is to retry with exponential backoff, computed as min((2^n) plus a random number of milliseconds, a maximum of 32 or 64 seconds, where n grows with each attempt, so retries spread out instead of arriving together.
List methods page through results with a pageToken: each response carries a nextPageToken to fetch the following page, and the maxResults parameter sets the page size. The events list also returns a nextSyncToken once the full result has been read, and passing it on a later call returns only the entries that changed since, which is incremental sync. An expired sync token returns 410 fullSyncRequired, meaning the stored data must be wiped and re-synced.
Responses are JSON. The events list defaults to 250 results per page and allows up to 2,500, while other collections have their own defaults. There is no single documented overall payload size limit across the API.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | badRequest | A required field or parameter is missing, a value is invalid, or the combination of fields is invalid. | Read the error message, fix the request, and do not retry it unchanged. |
| 401 | authError | The access token is missing, expired, or invalid. | Refresh the access token, or have the user re-authenticate through OAuth 2.0, then retry. |
| 403 | rateLimitExceeded / userRateLimitExceeded | The per-minute request rate was exceeded, for the project or for a single user. | Slow down and retry with exponential backoff; raise the per-user quota in the Google Cloud console if it is consistently hit. |
| 403 | quotaExceeded / forbiddenForNonOrganizer | A Calendar protection limit was reached, or a shared event property was changed by someone who is not the event's organizer. | Review the Calendar usage limits, or have the organizer make the change and use patch to touch only the fields needed. |
| 404 | notFound | The specified calendar, event, or rule was not found, or the token cannot see it. | Confirm the id and that the token's scopes reach the resource, then retry with backoff. |
| 409 | duplicate / conflict | The identifier already exists, or a batched item conflicts with another item in the same batch. | Use a new id or switch to update, or retry the remaining batch items on their own. |
| 410 | fullSyncRequired | The sync token is no longer valid, so an incremental sync cannot continue. | Discard the stored sync token and data, then run a full sync from scratch to get a fresh token. |
| 412 | conditionNotMet | The etag in the If-Match header no longer matches the resource's current etag, so it changed since it was read. | Re-fetch the resource to get the current etag, reapply the change, and resend. |
| 429 | rateLimitExceeded | Too many requests were sent in a short window. | Back off with exponential delay and jitter, then retry. |
| 500 | backendError | An unexpected error occurred on Google's side while processing the request. | Retry with exponential backoff; if it persists, the issue is server-side. |
The Google Calendar API has one version, v3, carried in the request path. New behavior ships through dated release notes rather than a new version number.
The Google Calendar API has a single version, v3, carried in the request path. There is no dated version header. New behavior ships as additive changes announced in the release notes, so an integration pins to v3 and tracks the notes for changes. The entries below are notable dated changes from the release notes, newest first.
Announced 27 October 2025 and effective 10 November 2025: each secondary calendar now has a single data owner, only the data owner can delete a calendar, and ownership transfers were initially restricted to UI changes (later opened to the API in June 2026).
Announced 5 August 2024 and effective 17 September 2024: birthdays surface as a birthday eventType with annual recurrence and a limited set of supported properties. A November 2024 follow-up exposed birthdayProperties for event data and contact references.
Announced 17 May 2024 and effective 3 June 2024: a batched operation whose item conflicts with another item in the same batch returns HTTP 409 Conflict, and the guidance is to retry the remaining items separately.
An integration pins to v3 and tracks the release notes for additive changes.
Google Calendar API release notes ↗Bollard AI sits between a team's AI agents and Google Calendar. Grant each agent exactly the access it needs, read or write, resource by resource, and every call is checked and logged.