Calendar API
All endpoints require authentication and calendar tool permissions. Calendar events are fetched from Google Calendar via service account delegation, combined with synthetic events from Nucleus data.
List Calendars
Section titled “List Calendars”GET /api/calendar/calendarsPermission: calendar / view
Returns the user’s primary Google Calendar and the shared Tribe calendar.
Response: { calendars }
Returns { calendars: [] } if Google Calendar is not configured.
List Events
Section titled “List Events”GET /api/calendar/eventsPermission: calendar / view
Query parameters:
| Param | Type | Description |
|---|---|---|
timeMin | string | Start of date range (ISO 8601, required) |
timeMax | string | End of date range (ISO 8601, required) |
calendarIds | string | Comma-separated calendar IDs (default: primary) |
Response: { events }
Events include both Google Calendar events and synthetic events based on user settings:
| Synthetic Type | Source | Color |
|---|---|---|
birthday | Users with date_of_birth | banana |
anniversary | Users with start_date | sage |
leave | Approved leave requests | peacock |
public_holiday | Public holidays table | tomato |
new_starter | Users starting in range | basil |
culture_event | Confirmed/planned events | grape |
Each synthetic event type can be toggled via calendar settings.
Create Event
Section titled “Create Event”POST /api/calendar/eventsPermission: calendar / update
Creates a Google Calendar event.
Request body:
| Field | Type | Description |
|---|---|---|
calendarId | string | Target calendar ID (required) |
summary | string | Event title |
description | string | Event description |
location | string | Event location |
start | object | { dateTime?, date?, timeZone? } |
end | object | { dateTime?, date?, timeZone? } |
attendees | array | Optional list of { email, displayName? } invitees. Google sends invite emails (sendUpdates=all) |
Response: { event } (201)
On error, the worker returns { error, detail } where detail carries the underlying Google API message (e.g. "insufficient permissions"). Surfaces in the toast on the create form.
Update Event
Section titled “Update Event”PUT /api/calendar/events/:calendarId/:eventIdPermission: calendar / update
Fully updates a Google Calendar event.
Path parameters:
| Param | Type | Description |
|---|---|---|
calendarId | string | Calendar ID |
eventId | string | Event ID |
Request body:
| Field | Type | Description |
|---|---|---|
summary | string | Event title |
description | string | Event description |
location | string | Event location |
start | object | { dateTime?, date?, timeZone? } |
end | object | { dateTime?, date?, timeZone? } |
attendees | array | Optional { email, displayName? } list. Replaces the full attendee list — pass everyone you want kept |
Response: { event }
Patch Event
Section titled “Patch Event”PATCH /api/calendar/events/:calendarId/:eventIdPermission: calendar / update
Partially updates a Google Calendar event (e.g. move time via drag-and-drop).
Path parameters:
| Param | Type | Description |
|---|---|---|
calendarId | string | Calendar ID |
eventId | string | Event ID |
Request body:
| Field | Type | Description |
|---|---|---|
start | object | { dateTime?, date?, timeZone? } |
end | object | { dateTime?, date?, timeZone? } |
Response: { event }
Delete Event
Section titled “Delete Event”DELETE /api/calendar/events/:calendarId/:eventIdPermission: calendar / update
Path parameters:
| Param | Type | Description |
|---|---|---|
calendarId | string | Calendar ID |
eventId | string | Event ID |
Response: { ok: true }
RSVP to Event
Section titled “RSVP to Event”POST /api/calendar/events/:calendarId/:eventId/respondPermission: calendar / update
Updates the calling user’s responseStatus on a Google Calendar event. The
worker fetches the existing attendee list, replaces only the matching
attendee’s status, and PATCHes back with sendUpdates=all so the organiser
sees the response.
Also upserts a row into calendar_invite_seen so the next pass of the
invite-scan cron does not re-fire a meeting_invited notification for this
event.
Path parameters:
| Param | Type | Description |
|---|---|---|
calendarId | string | Calendar ID |
eventId | string | Event ID |
Request body:
| Field | Type | Description |
|---|---|---|
status | string | One of accepted, declined, tentative |
Response: { event }
Location Autocomplete
Section titled “Location Autocomplete”GET /api/calendar/placesPermission: calendar / view
Searches for locations using Nominatim (OpenStreetMap) for the event location picker.
Query parameters:
| Param | Type | Description |
|---|---|---|
q | string | Search query (min 2 characters) |
tz | string | User timezone (used to bias results to country) |
Response: { results } — array of { id, label } objects (up to 5).
Get Settings
Section titled “Get Settings”GET /api/calendar/settingsPermission: calendar / view
Returns the user’s calendar display preferences.
Response: { settings }
Default settings include default_view: "month", all synthetic event toggles enabled, and show_weekends: 0 (weekends hidden — month and week views render Mon–Fri only until the user opts in).
| Setting | Type | Description |
|---|---|---|
default_view | string | Calendar view (month, week, day) |
visible_calendar_ids | string | JSON array of visible calendar IDs |
show_birthdays | number | Show birthday events (0/1, default 1) |
show_anniversaries | number | Show work anniversary events (0/1, default 1) |
show_leave | number | Show approved leave (0/1, default 1) |
show_public_holidays | number | Show public holidays (0/1, default 1) |
show_new_starters | number | Show new starter events (0/1, default 1) |
show_events | number | Show culture events (0/1, default 1) |
show_weekends | number | Show Saturday/Sunday columns in month/week views (0/1, default 0) |
viewed_person_ids | string | JSON array of person IDs to filter by |
Update Settings
Section titled “Update Settings”PUT /api/calendar/settingsPermission: calendar / update
Saves the user’s calendar preferences. Uses upsert.
Request body: Same fields as the settings response (with arrays as native arrays, not JSON strings).
Response: { ok: true }