---
name: google-calendar-oauth-app
description: >-
  The Google Calendar API layer on top of the shared
  `google-cloud-console-oauth` skill — the Calendar scope family (sensitive,
  not restricted, so verification but no CASA assessment), the granular
  scopes, which APIs to enable, where Meet conferencing touches events, what a
  token can see across primary, secondary, shared and delegated calendars,
  `freebusy` as a minimal-access option, watch channels and quotas, and the
  Workspace admin settings that block Calendar. Use when asked to get Google
  Calendar OAuth credentials, register or scope a Calendar app, choose between
  `calendar`, `calendar.readonly`, `calendar.events` and `calendar.freebusy`,
  judge how heavy verification will be, or explain why a connection cannot see
  a shared or team calendar. Read `google-cloud-console-oauth` first for the
  console mechanics; use the relevant product skill for other Google products.
---

# Google Calendar OAuth2 App Registration

Calendar is the cheap one. Every Google Calendar scope is **sensitive, not restricted** — so an external app needs
brand and scope verification, but **no CASA security assessment and no annual re-assessment**. That single fact is
the most useful thing to know when planning a Calendar integration, because it is what separates a roughly
week-long review from the funded external engagement a Gmail or whole-Drive app signs up for.

What Calendar spends that saving on is *reach*. A single `calendar` or `calendar.readonly` grant exposes every
calendar in the user's list — their own, their colleagues', the team rooms, anything shared with them — at whatever
access level the calendar's ACL gives them. Getting the scope narrow enough that the review is easy to justify, and
knowing what the token can and cannot see once granted, is what this file is for. Everything else is shared.

## Built on: `google-cloud-console-oauth`

**Read `google-cloud-console-oauth` first, then this file.** It owns all the console mechanics, and this file does not
repeat them:

- Choosing/creating the Cloud project and organization, enabling APIs, and who may administer it.
- Configuring the app on the Google Auth Platform (Branding, Audience, Data Access, Clients) and creating a **Web
  application** client — the only type that yields a usable client secret.
- Redirect-URI rules (exact matching, HTTPS-only, propagation delay) and the platform's per-data-center callback list.
- The generic scope model: declaring every scope on Data Access, the non-sensitive / sensitive / restricted tiers, the
  rule that the app's tier is its most sensitive scope, and `access_type=offline` + `prompt=consent` as the only way
  to get a refresh token back.
- The client secret being shown and downloadable **only once at creation**, add-then-disable rotation, `Testing` vs
  `In production` and the seven-day refresh-token expiry, the unverified-app screen, the 100-user caps, and the
  Workspace admin API controls in their generic form.

If you are reading only this file, you are missing all of the above.

## Inputs to collect before you start

The base skill lists the console inputs. These are the Calendar-specific ones:

| Input | Notes |
| --- | --- |
| **Read-only or read-write?** | `calendar.readonly` / `calendar.events.readonly` vs `calendar` / `calendar.events` (§1) |
| **Events only, or calendar metadata, ACLs and settings too?** | Decides whether `calendar.events*` alone is enough (§1) |
| **Is availability all that's needed?** | `freebusy` is dramatically narrower and easy to justify at review (§5) |
| **Only calendars the app itself creates?** | `calendar.app.created` scopes the app to its own secondary calendars (§1) |
| **Do shared, team or delegated calendars matter?** | Changes what "it can't see that calendar" means (§4) |
| **Is Google Meet / conferencing in scope?** | Meet links vs Meet space metadata vs recording *files* are three different tiers (§3) |
| **Webhooks or polling?** | Watch channels have their own delivery and renewal constraints (§6) |
| **Consumer accounts, one Workspace customer, or multi-tenant?** | Decides whether `Internal` removes verification (base §7) |

## Quick Start

1. Work the base skill's console steps, and **enable the Google Calendar API** on the project — plus the Google Meet
   API if any Meet scope is requested (§2). A perfectly configured client against a project with the API disabled
   fails at the first API call, not at authorization.
2. Settle the scope set before touching Data Access: §1 (the family and its tier), §5 (`freebusy` as the floor).
3. Confirm no Meet, Drive or Gmail scope sneaks the app into the restricted tier (§3).
4. Declare exactly those scopes, request exactly those scopes, and expect sensitive-scope verification — demo video
   and per-scope justification, no security assessment (§1).
5. Finish the base skill's capture, round-trip and handoff steps, adding the Calendar checks in §9.

## Calendar platform state (verified 2026-09-20 — re-verify before trusting)

- **No Calendar scope is restricted.** Google's authoritative restricted-scope list covers Gmail, Drive, Fit, Chat,
  Data Portability, Photos Ambient and Health. Calendar appears nowhere on it. The core Calendar scopes are
  **sensitive** — Google's own verification material uses "reading events stored in Google Calendar" as its canonical
  example of a sensitive scope.
- **Google does not publish a per-scope tier table for Calendar** the way it does for Drive and Gmail. The
  authoritative label is the one the Cloud console's Data Access picker shows next to each scope. Read it there and
  record what it says rather than asserting a tier for the narrower scopes from memory.
- **The granular Calendar scopes exist and are current**: `calendar.events.owned`, `calendar.events.owned.readonly`,
  `calendar.events.freebusy`, `calendar.events.public.readonly`, `calendar.app.created`, `calendar.calendars`,
  `calendar.calendars.readonly`, `calendar.calendarlist`, `calendar.calendarlist.readonly`, `calendar.acls`,
  `calendar.acls.readonly`, alongside the long-standing `calendar`, `calendar.readonly`, `calendar.events`,
  `calendar.events.readonly`, `calendar.freebusy` and `calendar.settings.readonly`.
- **Domain verification for webhooks is no longer required.** Google's API Console help now states plainly that
  domain verification in the API Console is no longer needed for push notifications to work. Runbooks that send you
  to Search Console before calling `watch` are describing a retired step (§6).
- **Secondary calendars now have a single `dataOwner`** (rolled out from November 2025), only that owner can delete
  them, and a Calendar API ownership-transfer endpoint plus an organization-owned filter on the calendar list rolled
  out mid-2026. An app that creates calendars on a user's behalf inherits that ownership model (§4).

If the scope picker or the restricted list does not look like this, stop and report what you actually see.

## 1. The Calendar scope family

Every scope below is a `https://www.googleapis.com/auth/` URL; the table drops the prefix for width.

| Scope | Grants |
| --- | --- |
| `calendar` | See, edit, share and permanently delete **all** calendars the user can access |
| `calendar.readonly` | See and download any calendar the user can access |
| `calendar.events` | View and edit events on **all** the user's calendars |
| `calendar.events.readonly` | View events on all the user's calendars |
| `calendar.events.owned` | Create/change/delete events only on calendars the user **owns** |
| `calendar.events.owned.readonly` | See events only on calendars the user owns |
| `calendar.events.public.readonly` | See events on **public** calendars |
| `calendar.app.created` | Make secondary calendars, and manage events **only on those** |
| `calendar.calendars` / `.readonly` | Calendar properties (title, description, default time zone); the writable form also creates secondary calendars |
| `calendar.calendarlist` / `.readonly` | The user's subscription list — which calendars they see, and adding/removing entries |
| `calendar.acls` / `.readonly` | Sharing permissions on calendars the user owns |
| `calendar.settings.readonly` | The user's Calendar settings (time zone, locale, working-hours-style preferences) |
| `calendar.freebusy` | The user's own availability |
| `calendar.events.freebusy` | Availability on calendars the user has access to |
| `calendar.addons.*` | Calendar add-on execution and current-event access — for Workspace add-ons, not a server-side connector |

**Tier: sensitive, not restricted.** Concretely, for an `External` app this means:

- **Yes:** brand verification, a per-scope written justification, and an unlisted English demo video showing the
  end-to-end grant. Google quotes roughly **3–5 business days** when nothing needs clarification.
- **No:** no CASA assessment, no assurance level, no external assessor, no Letter of Validation, **no annual
  recertification**, and no permitted-application-type gate of the kind that blocks restricted Drive scopes outright.

That asymmetry is worth stating to whoever is planning the work, because Calendar is routinely budgeted as if it were
Gmail. It is not. The expensive Google reviews are Gmail and whole-Drive; Calendar is a form and a video.

**Choose the narrowest scope that does the job, and say why in the justification.** The reviewer is reading exactly
that. Three substitutions carry real weight and cost nothing to make:

- Only touching events? `calendar.events*` instead of `calendar` — Google's own scope guidance pushes this, and it
  drops calendar metadata, ACLs and settings out of the grant.
- Only the user's own calendars? `calendar.events.owned*` instead of `calendar.events` — this is the difference
  between "the events you own" and "every event on every calendar shared with you, including your CEO's."
- Only the app's own calendars? `calendar.app.created` — the app creates secondary calendars and can never read the
  user's existing ones. This is Calendar's nearest equivalent to Drive's `drive.file`, and unlike `drive.file` it does
  not need a separate picker UI. It cannot enumerate anything the app did not create, so it fits "write our bookings
  into a calendar" and does not fit "sync the user's schedule."

**The tier of the app is still the tier of its most sensitive scope** (base §5). A Calendar app is a cheap Calendar
app only until someone adds a Gmail or whole-Drive scope to the same project — see §3, which is exactly how it
happens.

## 2. Which APIs to enable

Enable on the Cloud project, before the first API call:

- **Google Calendar API** — for everything in §1. Without it, authorization succeeds and the first call returns `403`
  with `accessNotConfigured`.
- **Google Meet API** — separately, and only if a `meetings.space.*` scope is requested (§3).
- **Admin SDK** — only if the integration also enumerates users or transfers calendar ownership org-wide.

The CalDAV API is a separate, older interface to the same data with its own authorization story. If someone proposes
it, that is a design conversation, not a console setting.

## 3. Google Meet, conferencing, and the tier trap

Three different things get called "Meet support," and they sit in three different tiers. Getting this wrong is the
single most common way a cheap Calendar app turns into a restricted-tier app:

| What you want | What it needs | Tier |
| --- | --- | --- |
| Create or read a **Meet link on an event** | Just the Calendar event scope — send `conferenceDataVersion=1` and a `createRequest` | Sensitive (Calendar only) |
| **Meet space metadata**, conference records, participants | `meetings.space.created` (app's own spaces) or `meetings.space.readonly` (any space the user can reach) | Sensitive |
| Configure auto-artifacts on spaces, including ones Calendar created | `meetings.space.settings` | **Non-sensitive** |
| **Download the recording or transcript file** | `drive.readonly` or `drive.meet.readonly` — the files live in Drive | **Restricted** — CASA territory |

So conferencing *links* are free with the scope you already have. Meet *metadata* costs one more sensitive scope and
one more enabled API. Recording and transcript **files** cost the entire restricted-tier regime, because fetching them
is a Drive read, not a Meet read. If a requirement says "pull the meeting recording," stop and read the
`google-drive-oauth-app` skill before promising anything.

Discovery detail worth knowing: a calendar advertises which conference types it supports via
`conferenceProperties.allowedConferenceSolutionTypes` on the calendars and calendar-list resources, so "Meet links
don't get created" is often a calendar or Workspace-edition property rather than a scope problem. And before turning
conference support on in an app that already writes events, run a full sync — Google warns that an app unaware of
`conferenceData` can silently strip existing conferences off users' events on update.

## 4. What the token can actually see: primary, secondary, shared and delegated calendars

Calendar's access model is two layers deep, and the OAuth scope is only the outer one. **The scope says what kinds of
Calendar data the app may touch; the calendar's ACL says which calendars the authorizing user can reach at all.** A
perfectly granted `calendar` token sees nothing the user themselves could not see.

- **Primary calendar** — created with the account, addressed as the calendar ID `primary` (and usually also by the
  user's email address), cannot be deleted or un-owned.
- **Secondary calendars** — user-created, deletable, shareable, and since late 2025 each has exactly one `dataOwner`;
  only that owner may delete it. An app that creates calendars for a user is creating them under that model, so
  authenticate as the user rather than as a service identity if the user should own the result.
- **Calendars vs CalendarList** — two different collections that people conflate constantly. `Calendars` is the
  calendar itself and its global properties; `CalendarList` is *this user's subscription list*, with their colours
  and reminder overrides. Inserting into `Calendars` **creates** a calendar; inserting into `CalendarList` merely
  **subscribes** the user to one that already exists.
- **Sharing a calendar does not add it to anyone's list.** This is the number-one cause of "the app can't see our
  team calendar": the calendar was shared, the user never added it, so it is absent from `CalendarList` and the app
  never enumerates it. The fix is a `CalendarList` insert (or the user adding it in the UI) — not a new scope and
  certainly not a new client.

ACL roles, in ascending order, decide what a token reaching a calendar can do: `freeBusyReader` (busy blocks only,
no details), `reader`, `writerWithoutPrivateAccess` (added mid-2026 — read/write non-private events, private ones
appear as busy), `writer` (also sees ACLs and labels), `owner`. A calendar holds up to 6,000 ACL entries, and
grantees can be individual users, groups, a whole domain, or the public.

Two consequences to put in the handoff:

- **"Delegated access" in Calendar is an ACL grant, not an OAuth concept.** If a customer wants the app to manage an
  executive's calendar, the executive grants the connecting user `writer` or `owner` on it and the user subscribes to
  it. Nothing changes in the registration.
- **Domain-wide delegation is the other route**, and a genuinely different posture: a Workspace super administrator
  pre-authorizes a service account for chosen scopes and the app impersonates users without any individual consent
  screen. It is an admin-side decision with its own review inside the customer, not a fallback for a user consent
  that is failing.

## 5. `freebusy` as the minimal-access alternative

If the product only needs to know *when someone is busy* — scheduling, routing, availability widgets, conflict
detection — `freebusy` is the answer and it is a materially easier conversation at review than `calendar.readonly`.

- `freebusy.query` is authorized by any of `calendar`, `calendar.readonly`, `calendar.freebusy` or
  `calendar.events.freebusy`. Requesting only a `freebusy` scope keeps the grant to availability.
- The response is **busy time ranges only** — no titles, no attendees, no locations, no descriptions. That is exactly
  the sentence to put in a scope justification, and exactly the sentence that reassures a customer's security team.
- It can be asked about calendars the caller cannot fully read: a `freeBusyReader` grant is enough to get busy blocks
  back. Calendars the caller genuinely cannot reach come back with a per-calendar `error` object (typically
  `notFound`) inside an otherwise successful response — a partial result, not a failed request. Handle per-calendar
  errors, or an app will silently treat an unreachable colleague as free all week.
- The trade-off is real and worth stating: `freebusy` **cannot create, move or annotate events**, and cannot tell you
  *what* a meeting is. A booking product needs `calendar.events` (or `calendar.app.created`) to write.

Ask *is availability all we need?* before registering. Going from `calendar.readonly` down to `freebusy` later is a
re-consent event for every customer.

## 6. Push notifications and watch channels

Calendar supports `watch` on four resources: **Acl, CalendarList, Events and Settings**. Events and ACLs are watched
per calendar, so a multi-calendar sync means a channel per calendar; settings and the calendar list are per user.

The constraints that actually bite:

- **The receiving URL must be HTTPS with a genuinely valid certificate.** Self-signed, untrusted-issuer, revoked, or
  hostname-mismatched certificates are all rejected.
- **Domain verification is no longer required.** Google's API Console help now states that API Console domain
  verification is not needed for push notifications to work. Older guidance — and much of the community advice around
  the `Unauthorized WebHook callback channel` error — sends you to Search Console and the *Domain verification* page
  first. If a `watch` call is rejected on the callback URL today, verify the certificate and the exact URL before
  spending time on a step Google says it retired; if verifying the domain is the only thing that fixes it, record
  that as a live discrepancy against the current doc rather than assuming either source is right.
- **Channels expire and nothing renews them.** The expiry comes back on the `watch` response and in the
  `X-Goog-Channel-Expiration` header on every notification; the app must create a replacement channel with a fresh
  unique `id` before then, and tolerate an overlap window where two channels are live for one resource.
- **Notifications carry no body.** They tell you *something* changed, not what. Pair every channel with a
  `syncToken` incremental sync and fetch the delta on each ping.
- **Delivery is explicitly not 100% reliable.** Google says messages can be dropped; a correct integration re-syncs
  periodically regardless of whether a notification arrived.
- **A `410 GONE` on a `syncToken`** means the token was invalidated — expiry, or an ACL change on the calendar. The
  only recovery is to wipe the local copy and run a full sync. Design for it; it is routine, not exceptional.

## 7. Quotas and rate limits

Calendar's limits are per-minute and generous, and they are *not* an authorization problem — re-authorizing a
rate-limited connection fixes nothing and burns a consent.

- **10,000 requests per minute per project**, and **600 requests per minute per user per project**, on a sliding
  window, so a burst inside one minute throttles the next.
- Exceeding them returns **`403` with `usageLimits`**, or **`429`**, for the same condition. Any client that treats
  `403` as "permissions are wrong" will misdiagnose a throttle as a broken grant — map the rate-limit reasons to a
  retry path explicitly.
- Retry with truncated exponential backoff plus jitter — Google's own formula is
  `min(((2^n) + random_milliseconds), maximum_backoff)`, with the random part under 1,000 ms and the ceiling around
  32–64 seconds.
- **The per-minute quotas can be raised** from the Cloud console's Quotas page (approval is not guaranteed). The
  **daily ceiling of 1,000,000 requests per project cannot be increased.**
- A separate and easily-confused failure: **`403 Calendar usage limits exceeded`** is Calendar's own abuse-prevention
  limit hitting the *end user*, not your project quota. Backing off harder does not fix it; the user or their admin
  does.

## 8. What a Workspace admin can do to a Calendar app

Beyond the generic API controls in base §7, two Calendar-specific admin settings explain most "it works for everyone
except this customer" reports:

- **API controls scoped to Calendar** (*Admin console → Security → Access and data control → API controls*). An admin
  can set Calendar data access to **Restricted**, after which only apps explicitly marked Trusted — or given a
  specific Google-data grant — can touch Calendar at all; apps on Limited access are shut out of Calendar even if
  they work against that customer's other Google services. The remedy is theirs: allowlist the client ID for
  Calendar. Nothing in the registration changes.
- **Calendar external sharing settings** (*Admin console → Apps → Google Workspace → Calendar → Sharing settings*).
  An admin can cap what people outside the organization see at **"Only free/busy information (hide event details)."**
  When that is on, an app authorized by an outside user gets busy blocks where it expects titles and attendees — with
  a scope that is entirely correct and a token that is entirely valid. It looks like a mapping bug and it is a policy.
- **The Calendar service can be switched off** for an org or an OU altogether, which fails calls no allowlist can
  rescue.

## Product fact — what the Calendar connector asks for

> **As of 2026-09-20, Unified.to's Google Calendar connector requests**, per object and operation:
>
> - **Calendars, read:** `openid`, `profile`, `email`, `https://www.googleapis.com/auth/calendar.readonly`
> - **Calendars, write:** `openid`, `profile`, `email`, `https://www.googleapis.com/auth/calendar`
> - **Events, read:** `openid`, `profile`, `email`, `https://www.googleapis.com/auth/calendar.events.readonly`
> - **Events, write:** `openid`, `profile`, `email`, `https://www.googleapis.com/auth/calendar.events`
> - **Availability (busy), read:** `openid`, `profile`, `email`, `https://www.googleapis.com/auth/calendar.freebusy`,
>   `https://www.googleapis.com/auth/calendar.events.freebusy`
> - **Recordings, read:** `https://www.googleapis.com/auth/meetings.space.readonly` — and **only** that; no identity
>   scopes accompany it
> - **Login/identity only:** `openid`, `profile`, `email`
>
> Everything here is **sensitive at worst** — nothing restricted, so verification without a security assessment. Note
> the shape of it, though: the connector asks for the *broad* members of each family (`calendar.readonly`,
> `calendar`, `calendar.events`), not the narrower `*.owned` or `calendar.app.created` variants, so a grant reaches
> every calendar in the user's list. If the customer's use case is narrower, that is a conversation with the
> connector's owner, not a console setting.
>
> Auth quirks worth knowing: it uses the standard Google authorize and token endpoints, asks for offline access and
> forces the consent prompt (so a refresh token comes back on re-authorization, per base §5); it remaps Google's
> `403` + `rateLimitExceeded` / `Quota exceeded` responses to a `429`-style rate-limit error, which matches §7; and
> alongside user OAuth it supports a **Google service-account credential** path scoped to full calendar access — the
> domain-wide-delegation route in §4.
>
> Because every configuration pairs identity scopes with at least one Calendar scope, **the granular consent screen
> applies**: Google shows per-scope checkboxes whenever sign-in and non-sign-in scopes — or more than one
> non-sign-in scope — are requested together, and the user can approve identity while declining Calendar. Always
> read the granted `scope` back from the token response rather than assuming (§9).
>
> Scope sets change. This note is dated, not live; confirm with the connector's owner before submitting anything.

## 9. Calendar-specific end-to-end checks

On top of the base skill's authorize → refresh round trip:

1. Make one real Calendar read — list the calendar list, then list events on `primary` — and confirm the Google
   Calendar API is enabled and returning data.
2. **Compare the granted `scope` in the token response against what was requested.** With identity plus Calendar
   scopes the consent screen is granular, and a user who unticks Calendar produces a token that authenticates
   perfectly and 403s on every Calendar call.
3. Test with a user who has a **shared or team calendar they have not subscribed to**, and confirm you understand why
   it is absent from the calendar list (§4) before anyone reports it as a bug.
4. If availability is the use case, run a `freebusy.query` spanning a calendar the user can reach and one they cannot,
   and confirm the per-calendar `error` object is handled rather than read as "free".
5. If webhooks are in scope, create a channel, receive one notification, and confirm the app re-fetches with a
   `syncToken` — then force a `410` and confirm it full-syncs instead of stalling.
6. If Meet matters, create an event with `conferenceDataVersion=1` and confirm a conference is actually generated
   (the create request completes asynchronously — the status starts as `pending`).

| Symptom | Cause |
| --- | --- |
| Auth succeeds, every Calendar call `403 accessNotConfigured` | Google Calendar API not enabled on the project (§2) |
| Auth succeeds, Calendar calls 403 but identity works | User declined the Calendar scope on the granular consent screen (§9.2) |
| App sees the user's own calendar but not the team's | Calendar shared but never added to the user's list — `CalendarList`, not a scope (§4) |
| Events come back as untitled busy blocks | `freeBusyReader` ACL role, or the admin's external-sharing cap (§4, §8) |
| `freebusy` returns "free" for someone who is clearly busy | Per-calendar `error` inside a 200 response, unhandled (§5) |
| `403` / `429` with `usageLimits` under load | Per-minute quota, not authorization — back off, do not re-authorize (§7) |
| `403 Calendar usage limits exceeded` for one user only | Calendar's end-user abuse limit; the user or their admin must resolve it (§7) |
| `410` on an incremental sync | `syncToken` invalidated (expiry or an ACL change) — full resync (§6) |
| Webhooks stop after a while, silently | Channel expired; nothing auto-renews (§6) |
| `watch` rejected on the callback URL | Certificate or URL, not a missing domain verification — that step was retired (§6) |
| Conferences vanish from events the app updates | Updating events without `conferenceData` awareness; full-sync before enabling (§3) |
| One customer's users all fail, everyone else is fine | Their admin set Calendar API access to Restricted, or Calendar is off for the OU (§8) |

## Stop and ask

Beyond the base skill's list, hand back to a human when:

- Someone wants recordings or transcripts **as files** — that is a restricted Drive scope and a CASA assessment, not
  a Calendar feature (§3).
- The requirement could be met by `freebusy` or `calendar.app.created` but a broad `calendar` / `calendar.readonly`
  scope is being requested anyway. That is a product and review-burden decision, not a console choice (§1, §5).
- Anyone proposes narrowing or widening scopes on a live integration — every customer re-consents.
- Domain-wide delegation is on the table: it needs a customer's super administrator and their own internal review,
  and it changes the trust model, not just the plumbing (§4).
- A customer's admin has restricted Calendar API access or capped external sharing — the fix is theirs (§8).
- The Cloud console labels a Calendar scope as anything other than non-sensitive or sensitive, or the restricted list
  has grown to include Calendar. That would contradict the **Calendar platform state** section above.

## References

Calendar-specific only; the base skill carries the generic Google OAuth references. Verified to resolve on 2026-09-20.

- Choose Google Calendar API scopes (the full scope family) — https://developers.google.com/workspace/calendar/api/auth
- Calendar API overview — https://developers.google.com/workspace/calendar/api/guides/overview
- Events and calendars concepts (primary vs secondary, Calendars vs CalendarList) — https://developers.google.com/workspace/calendar/api/concepts/events-calendars
- Sharing and ACL concepts (access roles, grantees, limits) — https://developers.google.com/workspace/calendar/api/concepts/sharing
- `freebusy.query` reference (authorizing scopes, per-calendar errors) — https://developers.google.com/workspace/calendar/api/v3/reference/freebusy/query
- Calendar list reference — https://developers.google.com/workspace/calendar/api/v3/reference/calendarList
- ACL reference — https://developers.google.com/workspace/calendar/api/v3/reference/acl
- Push notifications (watch channels, HTTPS/cert rules, expiry) — https://developers.google.com/workspace/calendar/api/guides/push
- `Events: watch` reference — https://developers.google.com/workspace/calendar/api/v3/reference/events/watch
- Incremental sync with `syncToken` (and the 410) — https://developers.google.com/workspace/calendar/api/guides/sync
- Create events, including Meet conferencing — https://developers.google.com/workspace/calendar/api/guides/create-events
- Usage limits and quotas — https://developers.google.com/workspace/calendar/api/guides/quota
- Calendar API errors — https://developers.google.com/workspace/calendar/api/guides/errors
- Calendar API release notes — https://developers.google.com/workspace/calendar/release-notes
- Improved management of secondary calendars via the Calendar API (2026) — https://workspaceupdates.googleblog.com/2026/06/secondary-calendar-management-API.html
- Meet REST API: authenticate and authorize (Meet scope tiers) — https://developers.google.com/workspace/meet/api/guides/authenticate-authorize
- Meet REST API overview — https://developers.google.com/workspace/meet/api/guides/overview
- How to handle granular permissions — https://developers.google.com/identity/protocols/oauth2/resources/granular-permissions
- Granular OAuth consent in web apps and Workspace add-ons — https://workspaceupdates.googleblog.com/2025/11/granular-oauth-consent-in-webapps.html
- Restricted scopes list (Calendar is absent) — https://support.google.com/cloud/answer/13464325?hl=en
- Verifying domains for push notifications (now states it is no longer required) — https://support.google.com/googleapi/answer/7072069?hl=en
- Set Google Calendar sharing options (admin external-sharing cap) — https://support.google.com/a/answer/60765?hl=en
- Control which apps access Google Workspace data (per-service API controls) — https://support.google.com/a/answer/7281227?hl=en
