Google Calendar#
Google Calendar is registered for OAuth-backed API sync with sync-coupled user import. It pulls events from the authenticated user's primary calendar into a reviewable import session, proposes TeamBoost user mappings from event actors, and projects each event into the internal integrations task-create draft for operator review.
| Capability | Method | Status |
|---|---|---|
CSV_IMPORT |
— | Not built |
SYNC |
Pull primary-calendar events from Google Calendar API v3 | ✅ Built |
USER_IMPORT |
Event actors imported during sync | ✅ Built |
WEBHOOK |
— | Not built |
The endpoints below live under /api/v1/providers/google-calendar/.... The
authorization URL route and sync route require an organization-scoped user token.
The OAuth callback route is unauthenticated for provider redirects; the signed
state value supplies the organization binding.
OAuth Setup#
Google Calendar uses OAuth 2.0, not an API key. Configure these environment variables before using the OAuth routes:
GOOGLE_CALENDAR_CLIENT_ID=<google-oauth-client-id>
GOOGLE_CALENDAR_CLIENT_SECRET=<google-oauth-client-secret>
GOOGLE_CALENDAR_REDIRECT_URI=https://<host>/api/v1/providers/google-calendar/oauth/callback
GOOGLE_CALENDAR_SCOPES=https://www.googleapis.com/auth/calendar.readonly
The redirect URI must exactly match the URI configured on the Google OAuth
client. Missing app config returns oauth_provider_not_configured.
OAuth Authorization#
Start authorization:
GET /api/v1/providers/google-calendar/oauth/authorize?organization_id=<id>
Returns an authorization URL plus a signed, expiring state:
{
"status": "success",
"data": {
"provider": "google-calendar",
"authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth?...",
"state": "<signed-state>",
"expiresAt": "2026-07-01T12:10:00.000Z"
}
}
Complete the callback:
GET /api/v1/providers/google-calendar/oauth/callback?state=<signed-state>&code=<code>
The callback exchanges the code for Google OAuth tokens and stores an encrypted
OAUTH_TOKEN credential for the organization. The response returns only metadata:
{
"status": "success",
"message": "OAuth credential stored.",
"data": {
"provider": "google-calendar",
"configured": true,
"credentialType": "OAUTH_TOKEN",
"updatedAt": "2026-07-01T12:00:00.000Z"
}
}
Access and refresh tokens are never returned by an endpoint. Invalid or expired
state returns invalid_oauth_state; a provider callback error returns
oauth_authorization_failed; a failed code exchange returns
oauth_token_exchange_failed. See the shared
OAuth callback contract
for callback bounds, duplicate refusal, and the authenticated relay shape.
Credential Status And Verification#
The generic credential status, verify, and delete routes work for Google Calendar:
GET /api/v1/providers/google-calendar/credentials?organization_id=<id>
POST /api/v1/providers/google-calendar/credentials/verify?organization_id=<id>
DELETE /api/v1/providers/google-calendar/credentials?organization_id=<id>
Verification uses the stored OAuth access token to make a cheap CalendarList probe. If the token has expired, verification and sync refresh it before calling Google.
Importing From Google Calendar#
POST /api/v1/providers/google-calendar/imports/sync?organization_id=<id>
The first shipped sync is intentionally bounded:
- primary calendar only;
- expanded event instances (
singleEvents=true); - a review window from 7 days in the past through 90 days in the future;
- deleted/cancelled events included when the API returns them.
The adapter calls:
GET https://www.googleapis.com/calendar/v3/users/me/calendarListGET https://www.googleapis.com/calendar/v3/calendars/{calendarId}/events
CalendarList and Events pagination are followed. Google quota responses (429
and 403 usage-limit responses) are retried with bounded backoff. Invalid or
revoked OAuth tokens return credential errors, and refresh failures return
oauth_token_refresh_failed.
Projection Field Coverage#
| Google Calendar source | TeamBoost draft field | Notes |
|---|---|---|
Event summary |
title |
Missing or hidden summaries are blocking projectionErrors. |
| Event resource | type |
Calendar events default to OTHER with a mapping note. |
Event description |
description |
Passed through when present. |
Event status |
status |
confirmed and tentative map to NOT_STARTED; cancelled maps to CANCELED; tentative adds a mapping note. |
| Calendar priority | priority |
Calendar has no priority; defaults to UNKNOWN. |
| Event creator | creatorId |
Resolved through the user mapping when matched; otherwise left unset with a note. |
| Event attendees | ownerId |
Attendees are imported for user mapping but are not assigned as owners automatically. |
| Organizer | requestedById |
Preserved in descriptionJson; requester mapping is left unset until the product rule is confirmed. |
| Event start/end | plannedStartDate, estimatedStartDate, plannedEndDate |
Calendar length is not converted into TeamBoost effort duration. |
| Calendar summary | projectTitle |
|
| Calendar/event refs | descriptionJson |
Preserves calendar id, event id, iCalUID, HTML link, recurrence refs, visibility, actors, and raw start/end context. |
User Import During Sync#
USER_IMPORT rides sync. Proposed users come from event creator, organizer,
and attendees, deduped by provider id, email, then name. Google Calendar is not
a Workspace directory API; standalone directory import is not built.
Not Built Yet#
- CSV or
.icsfile import. - Calendar selection and per-organization sync window preferences.
- Persisted incremental sync token state.
- Google Calendar push notifications/webhooks.
- Standalone Google Workspace directory import.
- Live OAuth validation in this repo's automated tests; use a real Google Cloud OAuth client and test calendar for release smoke.