Calendar API

Calendar API compatibility

Reference for the Google Calendar API v3 methods, parameters, and event fields supported by Calendarpit, and what returns an explicit error.

Calendar API

Calendarpit serves the endpoints below. Access follows these rules:

  • Every supported /calendar/v3 endpoint requires a Calendarpit bearer token. See Local OAuth for scopes.
  • Access is limited to calendars owned by the authorized test user.
  • primary resolves to that user's primary calendar.
  • Unknown or unowned calendar IDs return 404 (notFound).
  • Exception: freebusy.query returns 200 and reports a per-calendar notFound error inside the response.

All paths in this table are relative to /calendar/v3.

MethodPathBehavior
GET/users/me/calendarListList owned calendars
POST/users/me/calendarListRestore an owned calendar to the list
GET, PUT, PATCH, DELETE/users/me/calendarList/{calendarId}Read, replace, patch, or remove a list entry
POST/users/me/calendarList/watchSubscribe to calendar-list changes
GET/calendars/{calendarId}Calendar metadata (id, summary, timeZone)
GET, POST/calendars/{calendarId}/eventsList or create events
GET, PUT, PATCH, DELETE/calendars/{calendarId}/events/{eventId}Read, replace, patch, or delete an event
GET/calendars/{calendarId}/events/{eventId}/instancesRecurring instances and exceptions
POST/freeBusyMerged, clipped busy ranges, up to 50 calendars
POST/calendars/{calendarId}/events/watchSubscribe to event changes
POST/channels/stopStop an event or calendar-list watch channel

The calendarList.list query parameters are listed under Lists and paging below.

Method coverage

Unsupported methods return an explicit error:

RequestResponse
Unrouted endpoint501 (unsupportedFeature)
calendars.update, calendars.patch, calendars.deleteToken, scope, and ownership checks first (401, 403, or 404), then 501
events.import404 (notFound)
events.quickAdd with text400 (unsupportedFeature)
events.quickAdd without text404
Unsupported HTTP method on the events collection or an existing event405 (methodNotAllowed)

events.import and events.quickAdd share the /events/{eventId} path. That is why they return these codes.

ResourceMethodSupportedNotes
Acldelete❌ACLs and shared-calendar access are not simulated
Aclget❌
Aclinsert❌
Acllist❌
Aclpatch❌
Aclupdate❌
Aclwatch❌Event and calendar-list watches do not cover ACLs
CalendarListlist✅Owned calendars; minAccessRole, showDeleted, showHidden
CalendarListdelete✅Removes a non-primary calendar from the list only
CalendarListget✅Same entry list returns for that calendar
CalendarListinsert✅Restores an owned calendar removed from the list
CalendarListpatch✅Preserves omitted writable fields
CalendarListupdate✅PUT replaces writable fields
CalendarListwatch✅Caller's list changes; loopback callbacks by default
Calendarsget✅Metadata of a calendar the test user owns
Calendarsclear❌Delete the events, or reset to the startup fixture
Calendarsdelete❌Use the admin UI or the management API
Calendarsinsert❌
Calendarspatch❌
CalendarstransferOwnership❌One owner per calendar, with no sharing model
Calendarsupdate❌
Channelsstop✅Stops an event or calendar-list watch channel
Colorsget❌Event colors 1–11 and calendar colors 1–24 need no endpoint
Eventslist✅Time bounds, paging, singleEvents, sync tokens, filters
Eventsget✅Includes cancelled tombstones and recurring instance IDs
Eventsinsert✅Returns 200 with the stored event
Eventsupdate✅PUT replaces writable fields
Eventspatch✅Preserves omitted fields
Eventsdelete✅Keeps a cancelled record for synchronization
Eventsinstances✅Recurring instances, exceptions, and originalStart
Eventswatch✅Loopback callbacks by default; retries and a delivery log
Eventsimport❌Create the event with insert
Eventsmove❌Delete and insert across calendars instead
EventsquickAdd❌No natural-language parsing
Freebusyquery✅Merged, clipped busy ranges, up to 50 calendars
Settingsget❌No per-user Google settings
Settingslist❌
Settingswatch❌

Events

Supported fields

  • id: matches [a-zA-Z0-9@._-]{1,128}. primary is not allowed. Duplicate IDs return 409 (duplicate).
  • summary, description, and location
  • start and end
  • transparency: opaque or transparent
  • status: confirmed, tentative, or cancelled
  • visibility: default, public, private, or confidential
  • colorId: "1"–"11"
  • attendees and attendeesOmitted
  • guestsCanModify, guestsCanInviteOthers, and guestsCanSeeOtherGuests
  • reminders and recurrence
  • conferenceData: requires conferenceDataVersion=1
  • hangoutLink
  • extendedProperties.private and extendedProperties.shared: string maps

Write endpoints also accept:

  • sendUpdates: all, externalOnly, or none
  • conferenceDataVersion: 0 or 1

Server-managed fields

  • Responses include organizer, creator, iCalUID, sequence, created, updated, and a quoted etag.
  • Write requests also accept kind, etag, created, updated, calendarId, and sequence. This lets you send a fetched event back unchanged.
  • In write requests, calendarId is the resolved calendar ID, not primary.
  • organizer, creator, iCalUID, recurringEventId, and originalStartTime are read-only. Updates accept unchanged values.
  • On events.insert, omit these read-only fields. Calendarpit sets them.
  • sequence increments on each update.
  • If-Match is checked on GET, PUT, PATCH, and DELETE of stored events. A mismatch returns 412 (conditionNotMet).

PUT and PATCH

  • PUT replaces writable fields. It resets omitted optional fields to defaults.
  • PATCH preserves omitted fields.
    • A supplied start or end object replaces the stored object. Its fields are not merged.
    • extendedProperties maps merge by key. null removes a key or a whole map.
  • All-day inputs accept dateTime: null and timeZone: null.

Deletion and tombstones

events.delete returns 204 and keeps a cancelled tombstone. If the event is already cancelled, it returns 410 (deleted).

MethodTombstones
events.getReturned
freebusy.queryExcluded
ListsExcluded unless showDeleted=true or updatedMin is set

With singleEvents=false, cancelled exceptions of a series stay visible in lists.

For recurrence, invitations, reminders, synthetic Meet links, and time rules, see Events, recurrence and time.

Calendar list

Entry shape

  • Calendar-list entries use kind: "calendar#calendarListEntry".
  • list and get return the same entry shape.

Each owned calendar starts on its owner's list with these values:

  • accessRole: "owner"
  • selected: true
  • colorId: "1" (backgroundColor: "#ac725e", foregroundColor: "#1d1d1d")
  • defaultReminders: []
  • primary
  • conferenceProperties.allowedConferenceSolutionTypes: ["hangoutsMeet"]

Some fields appear only in certain cases:

  • hidden is omitted unless true.
  • summaryOverride and notificationSettings are omitted when empty.
  • deleted: true appears only on removed or tombstoned entries.
  • description and location are omitted. Requests that include them are rejected with 400 (unsupportedFeature).

Writes and concurrency:

  • Read-only fields are kind, etag, id, summary, timeZone, accessRole, primary, deleted, and conferenceProperties.
  • Writes accept read-only fields only when unchanged. A mismatch returns 400 (invalidParameter).
  • id accepts primary when the path uses primary.
  • etag updates when entry settings change. It also updates when the calendar's summary, timeZone, or primary flag changes.
  • If-Match is checked on PATCH, PUT, and DELETE. A mismatch returns 412 (conditionNotMet).

Writing settings (patch, update, insert)

Writable per-user settings are summaryOverride, colorId, backgroundColor, foregroundColor, hidden, selected, defaultReminders, and notificationSettings.

  • They persist across SQLite restarts.
  • They clear on reset or fixture load.
  • summaryOverride requires a non-blank string of up to 10,000 characters. "" returns 400.

How each write treats omitted fields:

  • PATCH preserves omitted writable fields. null clears summaryOverride, defaultReminders, and notificationSettings.
  • PUT and insert (200) replace writable fields:
    • Omitted overrides, reminders, and notifications are cleared.
    • hidden and selected reset to false. Never-written entries stay selected: true.
    • colorId resets to "1" unless colors are supplied.
  • Unchanged writes return 200. They do not change the etag, invalidate calendar-list page tokens, or notify watch channels.

Colors

  • colorId accepts palette IDs "1"–"24". The foreground is "#1d1d1d".
  • Unknown IDs, and inherited names like "constructor", return 400.

With colorRgbFormat=true:

  • Every insert, patch, or update must include both backgroundColor and foregroundColor (#rrggbb). Otherwise it returns 400.
  • Any supplied colorId is ignored and set to the nearest palette color.

Without colorRgbFormat=true:

  • RGB fields may only repeat the displayed colors.
  • On PATCH, repeating the current colorId and RGB keeps custom colors.
  • PUT and insert must send colorRgbFormat=true to keep custom RGB colors.
  • A different colorId clears custom RGB.

Reminders and notifications

  • defaultReminders accepts up to 5 {method: "email" | "popup", minutes: 0–40320} items.
  • notificationSettings.notifications accepts up to 5 {method: "email", type} items.
    • type is one of eventCreation, eventChange, eventCancellation, eventResponse, or agenda.
    • type values must be unique. Duplicate types return 400.
  • Neither setting sends email.
  • PATCH {"notificationSettings": {}} keeps existing notifications.
  • [], null, or PUT without notifications clears them.

Two behaviors follow Google's reference docs and were not checked against live Google:

  • Ignoring colorId with colorRgbFormat=true
  • Preserving notifications on PATCH {"notificationSettings": {}}

Delete and insert

calendarList.delete (204) removes a non-primary calendar from the caller's list only.

  • The primary calendar returns 403 (cannotDeletePrimaryCalendar).
  • An already removed calendar returns 404.
  • The calendar and its events remain accessible to calendars.get, events.*, freebusy.query, and events.watch.
  • calendarList.get, patch, and update return 404 for it.

calendarList.insert restores a removed owned calendar (200).

  • It requires id. A missing id returns 400.
  • It never creates a calendar.
  • Already-listed calendars, including hidden ones and primary, return 409 (duplicate). To unhide a calendar, use patch.

Management API effects:

  • Deleting a primary calendar promotes the first remaining listed calendar.
  • If all calendars were removed from the list, it instead restores the first owned calendar to the list with its saved settings.
  • Setting primary: true also restores a removed calendar to the list.

Watch

calendarList.watch shares the loopback allowlist, delivery log, and channels.stop endpoint with events.watch. See Watch notifications.

  • It sends sync on open.
  • It then sends exists when a list write changes stored settings.
  • It also sends exists when the management API creates, updates, or deletes the user's calendars.
  • Event writes do not trigger it.
  • Other query parameters (including syncToken) return 400 (unsupportedFeature).
  • params (such as params.ttl) also returns 400 (unsupportedFeature).

Lists and paging

calendarList.list

calendarList.list accepts these parameters:

  • maxResults and pageToken
  • minAccessRole: freeBusyReader, reader, writer, or owner. All owned calendars have the owner role, so every valid value matches them.
  • showHidden: defaults to false. Then list omits hidden: true entries, but get still returns them.
  • showDeleted: see below.

The response includes a collection etag, but no nextSyncToken.

showDeleted=true includes deleted: true entries for:

  • Calendars removed with calendarList.delete: they keep their stored settings, even if hidden: true.
  • Tombstones of calendars deleted through the management API: they use default list settings. They keep primary: true if the deleted calendar was primary.

events.list

events.list accepts these parameters:

  • timeMin, timeMax, and updatedMin: RFC 3339 timestamps with an offset.
  • maxResults: 1–2500, default 250.
  • orderBy: startTime or updated. orderBy=startTime requires singleEvents=true.
  • pageToken, singleEvents, timeZone, showDeleted, syncToken, and iCalUID.
  • privateExtendedProperty=name=value and sharedExtendedProperty=name=value: repeatable filters. All must match.

Matching and ordering:

  • Time matching uses start < timeMax and end > timeMin.
  • Unordered lists sort by event ID.

If a calendar has an unbounded recurring series:

  • events.list requires timeMax whenever singleEvents=true or timeMin is set.
  • events.instances on that series always requires timeMax.

A missing timeMax returns 400 (unsupportedFeature).

Page tokens

  • Event list pages freeze a snapshot on the first page. Writes between pages do not skip items.
  • Event page tokens are bound to the query and the user.
  • Event page tokens expire after 1 hour. They clear on restart, reset, or fixture load.
  • Calendar-list page tokens invalidate on any data or calendar-list write. They are not persisted.
  • Expired or stale tokens return 410 (invalidPageToken).

For syncToken and nextSyncToken, see Incremental sync.

Explicit exclusions

These features are unsupported:

  • ACLs, shared calendars, and delegation
  • Calendar groups
  • Color palettes (colors.get)
  • User settings
  • Calendar-list sync tokens
  • ACL and settings watch
  • Free-text search (q)
  • eventTypes
  • Attachments
  • Real email delivery
  • Real Google Meet creation
  • Full OIDC

Request validation

  • Unknown body fields return 400 (unsupportedFeature).
  • Unknown query parameters, including fields, return 400 (unsupportedFeature) on every /calendar/v3 endpoint.
  • Exception: channels.stop ignores its query string.
  • Transport parameters (alt=json, prettyPrint, quotaUser, key) are accepted.
  • API keys never replace OAuth bearer tokens.
  • Calendarpit never proxies to or syncs with Google.

To manage calendars and reset data, see Test control API. To point a client at Calendarpit, see Connect your app.

On this page