Calendar

Calendars, events and recurring series, invitation replies, and finding free time.

Guides: Calendar, Meetings.

MethodPathOperationScope
GET/v1/accounts/{accountId}/calendarsList calendarsread
POST/v1/accounts/{accountId}/calendarsCreate a calendarwrite
PATCH/v1/accounts/{accountId}/calendars/{calendarId}Rename a calendar or change its colorwrite
DELETE/v1/accounts/{accountId}/calendars/{calendarId}Delete a calendarwrite
GET/v1/accounts/{accountId}/calendar-eventsList events in a time range, by startread
POST/v1/accounts/{accountId}/calendar-eventsCreate an event or a recurring serieswrite
GET/v1/accounts/{accountId}/calendar-events/{eventId}Get an event with its bodyread
PATCH/v1/accounts/{accountId}/calendar-events/{eventId}Change an event, one occurrence, or a whole serieswrite
DELETE/v1/accounts/{accountId}/calendar-events/{eventId}Delete an event, one occurrence, or a whole serieswrite
POST/v1/accounts/{accountId}/calendar-events/{eventId}/respondAccept, tentatively accept or decline an invitationwrite
POST/v1/accounts/{accountId}/availability/findFind busy times and common free slotsread
POST/v1/availability/findFind free slots across several accountsread

List calendars

GET
/v1/accounts/{accountId}/calendars

Runs in your browser against api.workwae.com with the key you enter. Use a read-only key, limited to a test account if you can.

Required scope: read.

Path Parameters

accountId*string
Formatuuid

Response Body

OK

application/json
  1. response
items*array<>
Example Request
curl -X GET 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendars'
Example Response
{  "items": [    {      "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",      "name": "string",      "description": "Production",      "owner": {        "name": "Ada Lovelace",        "address": "ada@example.com"      },      "isPrimary": true,      "access": "owner",      "canEdit": true,      "color": "string",      "timeZone": "Europe/Berlin",      "isHidden": true    }  ]}

Create a calendar

POST
/v1/accounts/{accountId}/calendars

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

Microsoft stores the name and, when given, color (#rrggbb); a description or time zone is provider_unsupported (the mailbox zone applies to every calendar). Google stores the name, description, time zone and color. CalDAV stores the name, description and color (Apple calendar-color); a time zone is provider_unsupported.

Required scope: write.

Path Parameters

accountId*string
Formatuuid

Request Body

application/json
  1. body
name*string
Length1 <= length <= 100
description?|null
color?|null
timeZone?|null

Response Body

OK

application/json
  1. response
id*string
Formatuuid
name*string
description*string|null
owner*|null
isPrimary*boolean
access*CalendarAccess
Value in"owner""writer""reader""freebusy"
canEdit*boolean
color*string|null
timeZone*string|null
isHidden*boolean
Example Request
curl -X POST 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendars' \  -H 'Content-Type: application/json' \  -d '{  "name": "string"}'
Example Response
{  "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",  "name": "string",  "description": "Production",  "owner": {    "name": "Ada Lovelace",    "address": "ada@example.com"  },  "isPrimary": true,  "access": "owner",  "canEdit": true,  "color": "string",  "timeZone": "Europe/Berlin",  "isHidden": true}
PATCH
/v1/accounts/{accountId}/calendars/{calendarId}

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

Same fields as create. The primary calendar can be renamed where the provider allows it. A calendar the account cannot write is calendar_read_only.

Required scope: write.

Path Parameters

accountId*string
Formatuuid
calendarId*string
Formatuuid

Request Body

application/json
  1. body
name?string
Length1 <= length <= 100
description?|null
color?|null
timeZone?|null

Response Body

OK

application/json
  1. response
id*string
Formatuuid
name*string
description*string|null
owner*|null
isPrimary*boolean
access*CalendarAccess
Value in"owner""writer""reader""freebusy"
canEdit*boolean
color*string|null
timeZone*string|null
isHidden*boolean
Example Request
curl -X PATCH 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendars/1fccaa1f-a2df-4d43-8053-6bbb769ff90c' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",  "name": "string",  "description": "Production",  "owner": {    "name": "Ada Lovelace",    "address": "ada@example.com"  },  "isPrimary": true,  "access": "owner",  "canEdit": true,  "color": "string",  "timeZone": "Europe/Berlin",  "isHidden": true}

Delete a calendar

DELETE
/v1/accounts/{accountId}/calendars/{calendarId}

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

Refused for the primary calendar (calendar_primary). Events in it leave the index with the calendar and are not announced one by one, as when a sync sees the calendar gone. A provider that still holds events deletes them with the calendar.

Required scope: write.

Path Parameters

accountId*string
Formatuuid
calendarId*string
Formatuuid

Response Body

OK

application/json
  1. response
Example Request
curl -X DELETE 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendars/1fccaa1f-a2df-4d43-8053-6bbb769ff90c'
Example Response
null
GET
/v1/accounts/{accountId}/calendar-events

Runs in your browser against api.workwae.com with the key you enter. Use a read-only key, limited to a test account if you can.

Returns singles, occurrences and exceptions overlapping [start, end), not series definitions. Only the sync window (by default 90 days back to 365 days ahead) is indexed.

Required scope: read.

Path Parameters

accountId*string
Formatuuid

Query Parameters

start*string
Formatdate-time
end*string
Formatdate-time
calendarId?string
Formatuuid
limit?integer
Range1 <= value <= 500
Default100
cursor?string
Length1 <= length <= 512

Response Body

OK

application/json
  1. response
items*array<>
nextCursor*|null
Example Request
curl -X GET 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events?start=2026-05-04T09%3A30%3A00.000Z&end=2026-05-04T09%3A30%3A00.000Z'
Example Response
{  "items": [    {      "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",      "calendarId": "1fccaa1f-a2df-4d43-8053-6bbb769ff90c",      "kind": "single",      "seriesId": "dea472e1-378c-4ba7-8ef7-4cf60ee33665",      "originalStart": "2026-05-04T09:30:00.000Z",      "subject": "Quarterly report",      "snippet": "Hi Ada, the numbers for the quarter are attached.",      "location": "string",      "start": {        "dateTime": "2026-05-04T09:30:00.000Z",        "date": "2026-05-04",        "timeZone": "Europe/Berlin"      },      "end": {        "dateTime": "2026-05-04T09:30:00.000Z",        "date": "2026-05-04",        "timeZone": "Europe/Berlin"      },      "isAllDay": true,      "organizer": {        "name": "Ada Lovelace",        "address": "ada@example.com"      },      "attendees": [        {          "name": "Ada Lovelace",          "address": "ada@example.com",          "type": "required",          "response": "none"        }      ],      "isOrganizer": true,      "selfResponse": "none",      "status": "confirmed",      "showAs": "free",      "sensitivity": "normal",      "onlineMeetingUrl": "string",      "onlineMeetingProvider": "string",      "iCalUid": "string",      "recurrence": [        "string"      ],      "recurrenceTimeZone": "string",      "cancelledStarts": [        "2019-08-24T14:15:22Z"      ],      "categories": [        "string"      ],      "hasAttachments": true,      "reminderMinutes": 0,      "webLink": "string",      "updatedAt": "2026-05-04T09:30:00.000Z"    }  ],  "nextCursor": "eyJ0eG5pZCI6IjQyIiwiaWQiOjEwMDF9"}
POST
/v1/accounts/{accountId}/calendar-events

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

onlineMeeting asks the provider for a Teams (Microsoft) or Meet (Google) link; onlineMeetingUrl attaches a link from another service (Zoom, Webex, ...), read back as onlineMeetingUrl. On Microsoft that link is the location's link (location defaults to the URL) and a join line is added to a body sent along. onlineMeetingService has Workwae create a Zoom or Webex meeting (recurring for a series) hosted by the account's own grant at the service, else by the tenant's server app as the service user with the mailbox's address, and attaches its join link the same way. The server app hosts only accounts whose address the provider verified (Gmail, Microsoft, IMAP signed in with OAuth): a password IMAP account's address is whatever was typed, so it needs its own grant. The meeting is created only once the account is active, and deleted again if anything fails before its link is saved. On an IMAP account whose CalDAV server does not schedule, the invitation is mailed from the account's SMTP server when notify is true and there are attendees; a missing SMTP server is refused before anything is created, and a send that fails after the event is created is logged and the event stands.

Required scope: write.

Path Parameters

accountId*string
Formatuuid

Request Body

application/json
  1. body
calendarId*string
Formatuuid
subject?string
Lengthlength <= 255
body?
location?string
Lengthlength <= 255
start*|
end*|
attendees?array<>
Itemsitems <= 500
Default[]
recurrence?array<>
Items1 <= items <= 20
showAs?string
Value in"free""busy""tentative""oof""working_elsewhere"
sensitivity?Sensitivity
Value in"normal""personal""private""confidential"
reminderMinutes?|null
onlineMeeting?boolean
Defaultfalse
onlineMeetingUrl?string
Formaturi
Lengthlength <= 2048
onlineMeetingService?MeetingService
Value in"zoom""webex"
notify?boolean
Defaulttrue

Response Body

OK

application/json
  1. response
id*string
Formatuuid
calendarId*string
Formatuuid
kind*EventKind
Value in"single""series""occurrence""exception"
seriesId*|null
originalStart*|null
subject*string|null
snippet*string|null
location*string|null
start*
end*
isAllDay*boolean
organizer*|null
attendees*array<>
isOrganizer*boolean
selfResponse*ResponseStatus
Value in"none""organizer""accepted""tentative""declined""needs_action"
status*EventStatus
Value in"confirmed""tentative""cancelled"
showAs*ShowAs
Value in"free""busy""tentative""oof""working_elsewhere""unknown"
sensitivity*Sensitivity
Value in"normal""personal""private""confidential"
onlineMeetingUrl*string|null
onlineMeetingProvider*string|null
iCalUid*string|null
recurrence*array<string>|null
recurrenceTimeZone*string|null
cancelledStarts*array<>|null
categories*array<string>
hasAttachments*boolean
reminderMinutes*integer|null
webLink*string|null
updatedAt*string
Formatdate-time
body*|null
Example Request
curl -X POST 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events' \  -H 'Content-Type: application/json' \  -d '{  "calendarId": "1fccaa1f-a2df-4d43-8053-6bbb769ff90c",  "start": {    "dateTime": "2026-05-04T09:30:00.000Z",    "timeZone": "Europe/Berlin"  },  "end": {    "dateTime": "2026-05-04T09:30:00.000Z",    "timeZone": "Europe/Berlin"  }}'
Example Response
{  "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",  "calendarId": "1fccaa1f-a2df-4d43-8053-6bbb769ff90c",  "kind": "single",  "seriesId": "dea472e1-378c-4ba7-8ef7-4cf60ee33665",  "originalStart": "2026-05-04T09:30:00.000Z",  "subject": "Quarterly report",  "snippet": "Hi Ada, the numbers for the quarter are attached.",  "location": "string",  "start": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "end": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "isAllDay": true,  "organizer": {    "name": "Ada Lovelace",    "address": "ada@example.com"  },  "attendees": [    {      "name": "Ada Lovelace",      "address": "ada@example.com",      "type": "required",      "response": "none"    }  ],  "isOrganizer": true,  "selfResponse": "none",  "status": "confirmed",  "showAs": "free",  "sensitivity": "normal",  "onlineMeetingUrl": "string",  "onlineMeetingProvider": "string",  "iCalUid": "string",  "recurrence": [    "string"  ],  "recurrenceTimeZone": "string",  "cancelledStarts": [    "2019-08-24T14:15:22Z"  ],  "categories": [    "string"  ],  "hasAttachments": true,  "reminderMinutes": 0,  "webLink": "string",  "updatedAt": "2026-05-04T09:30:00.000Z",  "body": {    "contentType": "text",    "content": "string"  }}
GET
/v1/accounts/{accountId}/calendar-events/{eventId}

Runs in your browser against api.workwae.com with the key you enter. Use a read-only key, limited to a test account if you can.

Works for every kind, including a series (its recurrence rule).

Required scope: read.

Path Parameters

accountId*string
Formatuuid
eventId*string
Formatuuid

Response Body

OK

application/json
  1. response
id*string
Formatuuid
calendarId*string
Formatuuid
kind*EventKind
Value in"single""series""occurrence""exception"
seriesId*|null
originalStart*|null
subject*string|null
snippet*string|null
location*string|null
start*
end*
isAllDay*boolean
organizer*|null
attendees*array<>
isOrganizer*boolean
selfResponse*ResponseStatus
Value in"none""organizer""accepted""tentative""declined""needs_action"
status*EventStatus
Value in"confirmed""tentative""cancelled"
showAs*ShowAs
Value in"free""busy""tentative""oof""working_elsewhere""unknown"
sensitivity*Sensitivity
Value in"normal""personal""private""confidential"
onlineMeetingUrl*string|null
onlineMeetingProvider*string|null
iCalUid*string|null
recurrence*array<string>|null
recurrenceTimeZone*string|null
cancelledStarts*array<>|null
categories*array<string>
hasAttachments*boolean
reminderMinutes*integer|null
webLink*string|null
updatedAt*string
Formatdate-time
body*|null
Example Request
curl -X GET 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events/b6d8444a-dc76-4be5-849f-414f1b681c88'
Example Response
{  "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",  "calendarId": "1fccaa1f-a2df-4d43-8053-6bbb769ff90c",  "kind": "single",  "seriesId": "dea472e1-378c-4ba7-8ef7-4cf60ee33665",  "originalStart": "2026-05-04T09:30:00.000Z",  "subject": "Quarterly report",  "snippet": "Hi Ada, the numbers for the quarter are attached.",  "location": "string",  "start": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "end": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "isAllDay": true,  "organizer": {    "name": "Ada Lovelace",    "address": "ada@example.com"  },  "attendees": [    {      "name": "Ada Lovelace",      "address": "ada@example.com",      "type": "required",      "response": "none"    }  ],  "isOrganizer": true,  "selfResponse": "none",  "status": "confirmed",  "showAs": "free",  "sensitivity": "normal",  "onlineMeetingUrl": "string",  "onlineMeetingProvider": "string",  "iCalUid": "string",  "recurrence": [    "string"  ],  "recurrenceTimeZone": "string",  "cancelledStarts": [    "2019-08-24T14:15:22Z"  ],  "categories": [    "string"  ],  "hasAttachments": true,  "reminderMinutes": 0,  "webLink": "string",  "updatedAt": "2026-05-04T09:30:00.000Z",  "body": {    "contentType": "text",    "content": "string"  }}
PATCH
/v1/accounts/{accountId}/calendar-events/{eventId}

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

Addressing an occurrence changes only that instance; addressing the series changes every occurrence. onlineMeetingUrl replaces a link from another service (as on create); null removes it (on Google, whatever conference the event has; on Microsoft, the location's link, leaving a Teams meeting alone). For an event whose Zoom or Webex meeting Workwae created, a new subject, start, end or recurrence moves that meeting too, and an onlineMeetingUrl other than its own join link deletes it (sending that link back replaces nothing); changing one occurrence leaves the meeting's series as it is. A missing or refused meeting connection is reported before anything changes; a service failure after the event changed is reported with the event changed (repeat the request). On an IMAP account whose CalDAV server does not schedule, an update of a meeting the account organizes is mailed from its SMTP server when it changes start, end, recurrence, location or attendees, to the attendees Workwae has indexed for it and those the request names; a missing SMTP server or too many attendees is refused before anything changes, and a send that fails after the change is logged and the change stands.

Required scope: write.

Path Parameters

accountId*string
Formatuuid
eventId*string
Formatuuid

Request Body

application/json
  1. body
subject?string
Lengthlength <= 255
body?
location?string
Lengthlength <= 255
start?|
end?|
attendees?array<>
Itemsitems <= 500
recurrence?array<>
Items1 <= items <= 20
showAs?string
Value in"free""busy""tentative""oof""working_elsewhere"
sensitivity?Sensitivity
Value in"normal""personal""private""confidential"
reminderMinutes?|null
onlineMeetingUrl?|null
notify?boolean
Defaulttrue

Response Body

OK

application/json
  1. response
id*string
Formatuuid
calendarId*string
Formatuuid
kind*EventKind
Value in"single""series""occurrence""exception"
seriesId*|null
originalStart*|null
subject*string|null
snippet*string|null
location*string|null
start*
end*
isAllDay*boolean
organizer*|null
attendees*array<>
isOrganizer*boolean
selfResponse*ResponseStatus
Value in"none""organizer""accepted""tentative""declined""needs_action"
status*EventStatus
Value in"confirmed""tentative""cancelled"
showAs*ShowAs
Value in"free""busy""tentative""oof""working_elsewhere""unknown"
sensitivity*Sensitivity
Value in"normal""personal""private""confidential"
onlineMeetingUrl*string|null
onlineMeetingProvider*string|null
iCalUid*string|null
recurrence*array<string>|null
recurrenceTimeZone*string|null
cancelledStarts*array<>|null
categories*array<string>
hasAttachments*boolean
reminderMinutes*integer|null
webLink*string|null
updatedAt*string
Formatdate-time
body*|null
Example Request
curl -X PATCH 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events/b6d8444a-dc76-4be5-849f-414f1b681c88' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",  "calendarId": "1fccaa1f-a2df-4d43-8053-6bbb769ff90c",  "kind": "single",  "seriesId": "dea472e1-378c-4ba7-8ef7-4cf60ee33665",  "originalStart": "2026-05-04T09:30:00.000Z",  "subject": "Quarterly report",  "snippet": "Hi Ada, the numbers for the quarter are attached.",  "location": "string",  "start": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "end": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "isAllDay": true,  "organizer": {    "name": "Ada Lovelace",    "address": "ada@example.com"  },  "attendees": [    {      "name": "Ada Lovelace",      "address": "ada@example.com",      "type": "required",      "response": "none"    }  ],  "isOrganizer": true,  "selfResponse": "none",  "status": "confirmed",  "showAs": "free",  "sensitivity": "normal",  "onlineMeetingUrl": "string",  "onlineMeetingProvider": "string",  "iCalUid": "string",  "recurrence": [    "string"  ],  "recurrenceTimeZone": "string",  "cancelledStarts": [    "2019-08-24T14:15:22Z"  ],  "categories": [    "string"  ],  "hasAttachments": true,  "reminderMinutes": 0,  "webLink": "string",  "updatedAt": "2026-05-04T09:30:00.000Z",  "body": {    "contentType": "text",    "content": "string"  }}
DELETE
/v1/accounts/{accountId}/calendar-events/{eventId}

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

Cancels the meeting for its attendees when the account organizes it. A Zoom or Webex meeting Workwae created for the event (a series, not one occurrence) is deleted after the provider event: a provider refusal leaves both, and once the event is gone a meeting the service cannot delete (connection gone or refused, service unreachable) is logged and stays at the service while the request still succeeds. On an IMAP account whose CalDAV server does not schedule, the cancellation is mailed from the account's SMTP server to the attendees Workwae has indexed; a missing SMTP server or too many attendees is refused before anything is deleted, and a send that fails after the deletion is logged.

Required scope: write.

Path Parameters

accountId*string
Formatuuid
eventId*string
Formatuuid

Query Parameters

notify?|
Defaulttrue
comment?string
Lengthlength <= 2000

Response Body

OK

application/json
  1. response
Example Request
curl -X DELETE 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events/b6d8444a-dc76-4be5-849f-414f1b681c88'
Example Response
null
POST
/v1/accounts/{accountId}/calendar-events/{eventId}/respond

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

Addressing an occurrence answers that instance; the series answers all of them. On an IMAP account whose CalDAV server does not schedule, the answer is mailed to the organizer from the account's SMTP server; a missing SMTP server is refused before anything changes, and a send that fails after the answer is recorded is logged.

Required scope: write.

Path Parameters

accountId*string
Formatuuid
eventId*string
Formatuuid

Request Body

application/json
  1. body
response*RsvpResponse
Value in"accepted""tentative""declined"
comment?string
Lengthlength <= 2000
notify?boolean
Defaulttrue

Response Body

OK

application/json
  1. response
id*string
Formatuuid
calendarId*string
Formatuuid
kind*EventKind
Value in"single""series""occurrence""exception"
seriesId*|null
originalStart*|null
subject*string|null
snippet*string|null
location*string|null
start*
end*
isAllDay*boolean
organizer*|null
attendees*array<>
isOrganizer*boolean
selfResponse*ResponseStatus
Value in"none""organizer""accepted""tentative""declined""needs_action"
status*EventStatus
Value in"confirmed""tentative""cancelled"
showAs*ShowAs
Value in"free""busy""tentative""oof""working_elsewhere""unknown"
sensitivity*Sensitivity
Value in"normal""personal""private""confidential"
onlineMeetingUrl*string|null
onlineMeetingProvider*string|null
iCalUid*string|null
recurrence*array<string>|null
recurrenceTimeZone*string|null
cancelledStarts*array<>|null
categories*array<string>
hasAttachments*boolean
reminderMinutes*integer|null
webLink*string|null
updatedAt*string
Formatdate-time
Example Request
curl -X POST 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events/b6d8444a-dc76-4be5-849f-414f1b681c88/respond' \  -H 'Content-Type: application/json' \  -d '{  "response": "accepted"}'
Example Response
{  "id": "c4e6a8b0-1d3f-4a5c-8e7b-9d1f3a5c7e9b",  "calendarId": "1fccaa1f-a2df-4d43-8053-6bbb769ff90c",  "kind": "single",  "seriesId": "dea472e1-378c-4ba7-8ef7-4cf60ee33665",  "originalStart": "2026-05-04T09:30:00.000Z",  "subject": "Quarterly report",  "snippet": "Hi Ada, the numbers for the quarter are attached.",  "location": "string",  "start": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "end": {    "dateTime": "2026-05-04T09:30:00.000Z",    "date": "2026-05-04",    "timeZone": "Europe/Berlin"  },  "isAllDay": true,  "organizer": {    "name": "Ada Lovelace",    "address": "ada@example.com"  },  "attendees": [    {      "name": "Ada Lovelace",      "address": "ada@example.com",      "type": "required",      "response": "none"    }  ],  "isOrganizer": true,  "selfResponse": "none",  "status": "confirmed",  "showAs": "free",  "sensitivity": "normal",  "onlineMeetingUrl": "string",  "onlineMeetingProvider": "string",  "iCalUid": "string",  "recurrence": [    "string"  ],  "recurrenceTimeZone": "string",  "cancelledStarts": [    "2019-08-24T14:15:22Z"  ],  "categories": [    "string"  ],  "hasAttachments": true,  "reminderMinutes": 0,  "webLink": "string",  "updatedAt": "2026-05-04T09:30:00.000Z"}
POST
/v1/accounts/{accountId}/availability/find

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

A read sent as a POST, the question not fitting a URL. One provider request covers every attendee (Microsoft getSchedule, Google freeBusy.query); the answer is cached briefly per account, attendees and range. An attendee whose free/busy cannot be read (unknown address, calendar not shared) is listed in unresolved and complete is false; by default such an attendee does not constrain the suggestions, and with requireAll no suggestions are made (withheldReason unresolved_attendees).

Required scope: read.

Path Parameters

accountId*string
Formatuuid

Request Body

application/json
  1. body
attendees*array<>
Items1 <= items <= 20
start*string
Formatdate-time
end*string
Formatdate-time
durationMinutes?integer
Range5 <= value <= 1440
Default30
stepMinutes?integer
Range5 <= value <= 1440
Default30
timeZone?string
Length1 <= length <= 64
Default"UTC"
workingHours?
maxSuggestions?integer
Range0 <= value <= 100
Default10
requireAll?boolean
Defaultfalse
includeAccount?boolean
Defaulttrue

Response Body

OK

application/json
  1. response
attendees*array<>
suggestions*array<>
complete*boolean
unresolved*array<string>
withheldReason*|null
Example Request
curl -X POST 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/availability/find' \  -H 'Content-Type: application/json' \  -d '{  "attendees": [    "ada@example.com"  ],  "start": "2026-05-04T09:30:00.000Z",  "end": "2026-05-04T09:30:00.000Z"}'
Example Response
{  "attendees": [    {      "address": "ada@example.com",      "busy": [        {          "start": "2026-05-04T09:30:00.000Z",          "end": "2026-05-04T09:30:00.000Z",          "status": "busy"        }      ],      "error": "string"    }  ],  "suggestions": [    {      "start": "2026-05-04T09:30:00.000Z",      "end": "2026-05-04T09:30:00.000Z"    }  ],  "complete": true,  "unresolved": [    "string"  ],  "withheldReason": "unresolved_attendees"}
POST
/v1/availability/find

Runs against the live API with the key you enter: this change really happens. Use a key limited to a test account.

Reads up to 20 of the tenant's accounts, each through its own calendar, and suggests slots where all of them are free (mode all) or at least one is (mode any, for round-robin), with the accounts free for each slot. Other attendees are looked up through the first account and must all be free in either mode. An account that cannot be read (calendar sync off, paused, needing a new sign-in, a provider failure) is listed in unresolved with its error: in mode all it does not constrain the suggestions, in mode any it is never offered as free; requireAll withholds every suggestion instead (withheldReason unresolved_attendees). A read sent as a POST, like the single-account question, and not open to credentials limited to specific accounts.

Required scope: read.

Request Body

application/json
  1. body
accountIds*array<>
Items1 <= items <= 20
mode?AvailabilityMode
Default"all"
Value in"all""any"
attendees?array<>
Itemsitems <= 20
Default[]
start*string
Formatdate-time
end*string
Formatdate-time
durationMinutes?integer
Range5 <= value <= 1440
Default30
stepMinutes?integer
Range5 <= value <= 1440
Default30
timeZone?string
Length1 <= length <= 64
Default"UTC"
workingHours?
maxSuggestions?integer
Range0 <= value <= 100
Default10
requireAll?boolean
Defaultfalse

Response Body

OK

application/json
  1. response
accounts*array<>
attendees*array<>
suggestions*array<>
complete*boolean
unresolved*array<string>
withheldReason*|null
Example Request
curl -X POST 'https://api.workwae.com/v1/availability/find' \  -H 'Content-Type: application/json' \  -d '{  "accountIds": [    "6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b"  ],  "start": "2026-05-04T09:30:00.000Z",  "end": "2026-05-04T09:30:00.000Z"}'
Example Response
{  "accounts": [    {      "address": "ada@example.com",      "busy": [        {          "start": "2026-05-04T09:30:00.000Z",          "end": "2026-05-04T09:30:00.000Z",          "status": "busy"        }      ],      "error": "string",      "accountId": "6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b"    }  ],  "attendees": [    {      "address": "ada@example.com",      "busy": [        {          "start": "2026-05-04T09:30:00.000Z",          "end": "2026-05-04T09:30:00.000Z",          "status": "busy"        }      ],      "error": "string"    }  ],  "suggestions": [    {      "start": "2026-05-04T09:30:00.000Z",      "end": "2026-05-04T09:30:00.000Z",      "accountIds": [        "6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b"      ]    }  ],  "complete": true,  "unresolved": [    "string"  ],  "withheldReason": "unresolved_attendees"}