Google Workspace
Calendar, Drive, Gmail and Contacts, connected per organisation with your own OAuth client and switched on per employee.
30 endpoints across 1 group. A permission written module.resource.action:own is scoped: :own covers rows that are yours, :any covers everyone’s, and :any satisfies a check for :own.
google
Section titled “google”| Endpoint | Permission |
|---|---|
GET /google/calendar/calendars | google.connection.manage |
PUT /google/calendar/calendars | google.connection.manage |
GET /google/calendar/channels | google.calendar.read |
GET /google/calendar/events | google.calendar.read |
POST /google/calendar/webhook | Deliberately open |
GET /google/connections | google.settings.manage |
GET /google/connections/me | google.connection.manage |
PATCH /google/connections/me | google.connection.manage |
POST /google/connections/me/disconnect | google.connection.manage |
GET /google/drive/browse | google.drive.read |
DELETE /google/drive/files/{drive_file_id} | google.drive.write |
PUT /google/drive/folder | google.drive.write |
POST /google/drive/folders | google.drive.write |
GET /google/drive/links | google.drive.read |
POST /google/drive/links | google.drive.write |
DELETE /google/drive/links/{link_id} | google.drive.write |
POST /google/drive/provision | google.drive.write |
POST /google/drive/provision-all | google.settings.manage |
GET /google/drive/state | google.drive.read |
POST /google/drive/upload-session | google.drive.write |
POST /google/gmail/import | interactions.interaction.write |
GET /google/gmail/lookup | google.connection.manage |
POST /google/gmail/refresh | google.connection.manage |
GET /google/gmail/search | google.connection.manage |
GET /google/gmail/status | google.connection.manage |
GET /google/gmail/threads/{thread_id} | google.connection.manage |
GET /google/oauth/callback | google.connection.manage |
GET /google/oauth/connect | google.connection.manage |
GET /google/settings | google.settings.manage |
PUT /google/settings | google.settings.manage |
Parameters and schemas per endpoint
GET /api/v1/google/calendar/calendars
Section titled “GET /api/v1/google/calendar/calendars”Calendar List — The viewer’s own calendarList — the selection UI’s read (#440). Briefly cached; the existing calendar.events scope covers it, so no re-consent is needed.
Permission: google.connection.manage
Returns: 200 · CalendarListEntry[]
PUT /api/v1/google/calendar/calendars
Section titled “PUT /api/v1/google/calendar/calendars”Set Calendar Selection — Choose which shared calendars sync for the viewer. Deselecting removes the calendar’s cached events on the spot; selecting queues a sync so the agenda fills without waiting.
Permission: google.connection.manage
Request body: CalendarSelection
Returns: 200 · CalendarListEntry[]
GET /api/v1/google/calendar/channels
Section titled “GET /api/v1/google/calendar/channels”Calendar Channels — The viewer’s selection off the database alone — what the Agenda’s feeds menu reads on every open, so it never costs a Google call.
Permission: google.calendar.read
Returns: 200 · SelectedCalendar[]
GET /api/v1/google/calendar/events
Section titled “GET /api/v1/google/calendar/events”Calendar Events — The viewer’s own cached Google events. Reads the local cache, never Google live.
Permission: google.calendar.read
Query parameters:
| Name | Type | Meaning |
|---|---|---|
date_from | string · required | |
date_to | string · required |
Returns: 200 · CalendarFeedItem[]
POST /api/v1/google/calendar/webhook
Section titled “POST /api/v1/google/calendar/webhook”Calendar Webhook
Permission: Deliberately open
Returns: 200
GET /api/v1/google/connections
Section titled “GET /api/v1/google/connections”List Connections
Permission: google.settings.manage
Returns: 200 · app__integrations__google__schemas__ConnectionRead[]
GET /api/v1/google/connections/me
Section titled “GET /api/v1/google/connections/me”My Connection
Permission: google.connection.manage
Returns: 200 · MyConnectionRead
PATCH /api/v1/google/connections/me
Section titled “PATCH /api/v1/google/connections/me”Update My Connection
Permission: google.connection.manage
Request body: MyConnectionUpdate
Returns: 200 · MyConnectionRead
POST /api/v1/google/connections/me/disconnect
Section titled “POST /api/v1/google/connections/me/disconnect”Disconnect My Connection
Permission: google.connection.manage
Returns: 204
GET /api/v1/google/drive/browse
Section titled “GET /api/v1/google/drive/browse”Browse — Live folder contents as the viewing user — Drive’s permissions are authoritative.
Permission: google.drive.read
Query parameters:
| Name | Type | Meaning |
|---|---|---|
folder_id | string | |
q | string | |
refresh | boolean | (default false) |
Returns: 200 · DriveBrowseResult
DELETE /api/v1/google/drive/files/{drive_file_id}
Section titled “DELETE /api/v1/google/drive/files/{drive_file_id}”Trash File — Move a Drive file to Drive’s bin — the other half of unlink (#394).
Permission: google.drive.write
Path parameters: drive_file_id
Returns: 204
PUT /api/v1/google/drive/folder
Section titled “PUT /api/v1/google/drive/folder”Set Folder — Point a record at an existing Drive folder — the picker’s target.
Permission: google.drive.write
Request body: DriveFolderSet
Returns: 200 · DriveLinkRead
POST /api/v1/google/drive/folders
Section titled “POST /api/v1/google/drive/folders”Create Folder — Create a subfolder inside the folder being browsed, as the viewing user (issue #21).
Permission: google.drive.write
Request body: DriveFolderCreate
Returns: 201 · DriveFolder
GET /api/v1/google/drive/links
Section titled “GET /api/v1/google/drive/links”List Links
Permission: google.drive.read
Query parameters:
| Name | Type | Meaning |
|---|---|---|
entity_type | string · required | |
entity_id | string · required | |
rollup | boolean | (default false) |
limit | integer | Cap the page a panel draws (#407); ask for one more than you keep to learn there are more. Absent means every link, which is what the roll-up view needs — a roll-up folds a project’s tasks in after the query and cannot be cut before it. |
Returns: 200 · DriveLinkRead[]
POST /api/v1/google/drive/links
Section titled “POST /api/v1/google/drive/links”Create Link
Permission: google.drive.write
Request body: DriveLinkCreate
Returns: 201 · DriveLinkRead
DELETE /api/v1/google/drive/links/{link_id}
Section titled “DELETE /api/v1/google/drive/links/{link_id}”Delete Link — Unlink only. The Drive file is never touched (issue #21 — the dialog says so too).
Permission: google.drive.write
Path parameters: link_id
Returns: 204
POST /api/v1/google/drive/provision
Section titled “POST /api/v1/google/drive/provision”Provision Entity — Queue one entity’s folder — the panel’s “create folder” button.
Permission: google.drive.write
Request body: DriveProvisionRequest
Returns: 202
POST /api/v1/google/drive/provision-all
Section titled “POST /api/v1/google/drive/provision-all”Provision All — Backfill: a folder for every client that has none (Instellingen → Google).
Permission: google.settings.manage
Returns: 200 · DriveBulkProvisionResult
GET /api/v1/google/drive/state
Section titled “GET /api/v1/google/drive/state”Drive State — Provisioning readiness + this entity’s folder-job status, for the panels (#444).
Permission: google.drive.read
Query parameters:
| Name | Type | Meaning |
|---|---|---|
entity_type | string | |
entity_id | string |
Returns: 200 · DriveStateRead
POST /api/v1/google/drive/upload-session
Section titled “POST /api/v1/google/drive/upload-session”Create Upload Session
Permission: google.drive.write
Request body: DriveUploadSessionCreate
Returns: 200 · DriveUploadSession
POST /api/v1/google/gmail/import
Section titled “POST /api/v1/google/gmail/import”Import Gmail Message — Log one message the poller skipped, filed where the caller says.
Permission: interactions.interaction.write
Request body: GmailImportRequest
Returns: 201 · GmailImportResult
GET /api/v1/google/gmail/lookup
Section titled “GET /api/v1/google/gmail/lookup”Lookup Gmail Message — Resolve a pasted reference to the message(s) it names, in the caller’s own mailbox.
Permission: google.connection.manage
Query parameters:
| Name | Type | Meaning |
|---|---|---|
reference | string · required | A Gmail link, a message/thread id, or an RFC-822 Message-ID |
Returns: 200 · GmailLookupResult
POST /api/v1/google/gmail/refresh
Section titled “POST /api/v1/google/gmail/refresh”Refresh Gmail — Poll this mailbox once, now — rate-limited to one manual poll per minute.
Permission: google.connection.manage
Returns: 200 · GmailRefreshResult
GET /api/v1/google/gmail/search
Section titled “GET /api/v1/google/gmail/search”Search Gmail — Find a message in the caller’s own mailbox, by who it was with and when (#372).
Permission: google.connection.manage
Query parameters:
| Name | Type | Meaning |
|---|---|---|
participant | string | |
subject | string | |
after | string | |
before | string |
Returns: 200 · GmailSearchResult
GET /api/v1/google/gmail/status
Section titled “GET /api/v1/google/gmail/status”Read Gmail Status — When this mailbox was last polled, and whether asking for another one is worth it.
Permission: google.connection.manage
Returns: 200 · GmailSyncStatus
GET /api/v1/google/gmail/threads/{thread_id}
Section titled “GET /api/v1/google/gmail/threads/{thread_id}”Read Gmail Thread — Every message of one conversation, marked with what is already on the timeline.
Permission: google.connection.manage
Path parameters: thread_id
Returns: 200 · GmailLookupResult
GET /api/v1/google/oauth/callback
Section titled “GET /api/v1/google/oauth/callback”Google Oauth Callback — Store the grant and land the browser back where the connect started.
Permission: google.connection.manage
Returns: 200
GET /api/v1/google/oauth/connect
Section titled “GET /api/v1/google/oauth/connect”Oauth Connect — 302 to Google’s consent screen, asking exactly the enabled surfaces’ scopes.
Permission: google.connection.manage
Query parameters:
| Name | Type | Meaning |
|---|---|---|
include_gmail | boolean | (default false) |
include_marketing | boolean | (default false) |
include_analytics | boolean | (default false) |
include_search_console | boolean | (default false) |
include_ads | boolean | (default false) |
include_tag_manager | boolean | (default false) |
next | string | (default “) |
Returns: 200
GET /api/v1/google/settings
Section titled “GET /api/v1/google/settings”Get Settings
Permission: google.settings.manage
Returns: 200 · GoogleSettingsRead
PUT /api/v1/google/settings
Section titled “PUT /api/v1/google/settings”Save Settings
Permission: google.settings.manage
Request body: GoogleSettingsWrite
Returns: 200 · GoogleSettingsRead