Calendar
Calendars, events and recurring series, invitation replies, and finding free time.
| Method | Path | Operation | Scope |
|---|---|---|---|
GET | /v1/accounts/{accountId}/calendars | List calendars | read |
POST | /v1/accounts/{accountId}/calendars | Create a calendar | write |
PATCH | /v1/accounts/{accountId}/calendars/{calendarId} | Rename a calendar or change its color | write |
DELETE | /v1/accounts/{accountId}/calendars/{calendarId} | Delete a calendar | write |
GET | /v1/accounts/{accountId}/calendar-events | List events in a time range, by start | read |
POST | /v1/accounts/{accountId}/calendar-events | Create an event or a recurring series | write |
GET | /v1/accounts/{accountId}/calendar-events/{eventId} | Get an event with its body | read |
PATCH | /v1/accounts/{accountId}/calendar-events/{eventId} | Change an event, one occurrence, or a whole series | write |
DELETE | /v1/accounts/{accountId}/calendar-events/{eventId} | Delete an event, one occurrence, or a whole series | write |
POST | /v1/accounts/{accountId}/calendar-events/{eventId}/respond | Accept, tentatively accept or decline an invitation | write |
POST | /v1/accounts/{accountId}/availability/find | Find busy times and common free slots | read |
POST | /v1/availability/find | Find free slots across several accounts | read |
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.
accountId*stringuuidOK
application/json- response
items*array<>curl -X GET 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendars'{ "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 } ]}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.
accountId*stringuuidapplication/json- body
name*string1 <= length <= 100description?|nullcolor?|nulltimeZone?|nullOK
application/json- response
id*stringuuidname*stringdescription*string|nullowner*|nullisPrimary*booleanaccess*CalendarAccess"owner""writer""reader""freebusy"canEdit*booleancolor*string|nulltimeZone*string|nullisHidden*booleancurl -X POST 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendars' \ -H 'Content-Type: application/json' \ -d '{ "name": "string"}'{ "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}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.
accountId*stringuuidcalendarId*stringuuidapplication/json- body
name?string1 <= length <= 100description?|nullcolor?|nulltimeZone?|nullOK
application/json- response
id*stringuuidname*stringdescription*string|nullowner*|nullisPrimary*booleanaccess*CalendarAccess"owner""writer""reader""freebusy"canEdit*booleancolor*string|nulltimeZone*string|nullisHidden*booleancurl -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 '{}'{ "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}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.
accountId*stringuuidcalendarId*stringuuidOK
application/json- response
curl -X DELETE 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendars/1fccaa1f-a2df-4d43-8053-6bbb769ff90c'nullRuns 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.
accountId*stringuuidstart*stringdate-timeend*stringdate-timecalendarId?stringuuidlimit?integer1 <= value <= 500100cursor?string1 <= length <= 512OK
application/json- response
items*array<>nextCursor*|nullcurl -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'{ "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"}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.
accountId*stringuuidapplication/json- body
calendarId*stringuuidsubject?stringlength <= 255body?location?stringlength <= 255start*|end*|attendees?array<>items <= 500[]recurrence?array<>1 <= items <= 20showAs?string"free""busy""tentative""oof""working_elsewhere"sensitivity?Sensitivity"normal""personal""private""confidential"reminderMinutes?|nullonlineMeeting?booleanfalseonlineMeetingUrl?stringurilength <= 2048onlineMeetingService?MeetingService"zoom""webex"notify?booleantrueOK
application/json- response
id*stringuuidcalendarId*stringuuidkind*EventKind"single""series""occurrence""exception"seriesId*|nulloriginalStart*|nullsubject*string|nullsnippet*string|nulllocation*string|nullstart*end*isAllDay*booleanorganizer*|nullattendees*array<>isOrganizer*booleanselfResponse*ResponseStatus"none""organizer""accepted""tentative""declined""needs_action"status*EventStatus"confirmed""tentative""cancelled"showAs*ShowAs"free""busy""tentative""oof""working_elsewhere""unknown"sensitivity*Sensitivity"normal""personal""private""confidential"onlineMeetingUrl*string|nullonlineMeetingProvider*string|nulliCalUid*string|nullrecurrence*array<string>|nullrecurrenceTimeZone*string|nullcancelledStarts*array<>|nullcategories*array<string>hasAttachments*booleanreminderMinutes*integer|nullwebLink*string|nullupdatedAt*stringdate-timebody*|nullcurl -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" }}'{ "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" }}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.
accountId*stringuuideventId*stringuuidOK
application/json- response
id*stringuuidcalendarId*stringuuidkind*EventKind"single""series""occurrence""exception"seriesId*|nulloriginalStart*|nullsubject*string|nullsnippet*string|nulllocation*string|nullstart*end*isAllDay*booleanorganizer*|nullattendees*array<>isOrganizer*booleanselfResponse*ResponseStatus"none""organizer""accepted""tentative""declined""needs_action"status*EventStatus"confirmed""tentative""cancelled"showAs*ShowAs"free""busy""tentative""oof""working_elsewhere""unknown"sensitivity*Sensitivity"normal""personal""private""confidential"onlineMeetingUrl*string|nullonlineMeetingProvider*string|nulliCalUid*string|nullrecurrence*array<string>|nullrecurrenceTimeZone*string|nullcancelledStarts*array<>|nullcategories*array<string>hasAttachments*booleanreminderMinutes*integer|nullwebLink*string|nullupdatedAt*stringdate-timebody*|nullcurl -X GET 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events/b6d8444a-dc76-4be5-849f-414f1b681c88'{ "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" }}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.
accountId*stringuuideventId*stringuuidapplication/json- body
subject?stringlength <= 255body?location?stringlength <= 255start?|end?|attendees?array<>items <= 500recurrence?array<>1 <= items <= 20showAs?string"free""busy""tentative""oof""working_elsewhere"sensitivity?Sensitivity"normal""personal""private""confidential"reminderMinutes?|nullonlineMeetingUrl?|nullnotify?booleantrueOK
application/json- response
id*stringuuidcalendarId*stringuuidkind*EventKind"single""series""occurrence""exception"seriesId*|nulloriginalStart*|nullsubject*string|nullsnippet*string|nulllocation*string|nullstart*end*isAllDay*booleanorganizer*|nullattendees*array<>isOrganizer*booleanselfResponse*ResponseStatus"none""organizer""accepted""tentative""declined""needs_action"status*EventStatus"confirmed""tentative""cancelled"showAs*ShowAs"free""busy""tentative""oof""working_elsewhere""unknown"sensitivity*Sensitivity"normal""personal""private""confidential"onlineMeetingUrl*string|nullonlineMeetingProvider*string|nulliCalUid*string|nullrecurrence*array<string>|nullrecurrenceTimeZone*string|nullcancelledStarts*array<>|nullcategories*array<string>hasAttachments*booleanreminderMinutes*integer|nullwebLink*string|nullupdatedAt*stringdate-timebody*|nullcurl -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 '{}'{ "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" }}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.
accountId*stringuuideventId*stringuuidnotify?|truecomment?stringlength <= 2000OK
application/json- response
curl -X DELETE 'https://api.workwae.com/v1/accounts/6f1c2a4e-8b3d-4e5f-9a7b-1c2d3e4f5a6b/calendar-events/b6d8444a-dc76-4be5-849f-414f1b681c88'nullRuns 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.
accountId*stringuuideventId*stringuuidapplication/json- body
response*RsvpResponse"accepted""tentative""declined"comment?stringlength <= 2000notify?booleantrueOK
application/json- response
id*stringuuidcalendarId*stringuuidkind*EventKind"single""series""occurrence""exception"seriesId*|nulloriginalStart*|nullsubject*string|nullsnippet*string|nulllocation*string|nullstart*end*isAllDay*booleanorganizer*|nullattendees*array<>isOrganizer*booleanselfResponse*ResponseStatus"none""organizer""accepted""tentative""declined""needs_action"status*EventStatus"confirmed""tentative""cancelled"showAs*ShowAs"free""busy""tentative""oof""working_elsewhere""unknown"sensitivity*Sensitivity"normal""personal""private""confidential"onlineMeetingUrl*string|nullonlineMeetingProvider*string|nulliCalUid*string|nullrecurrence*array<string>|nullrecurrenceTimeZone*string|nullcancelledStarts*array<>|nullcategories*array<string>hasAttachments*booleanreminderMinutes*integer|nullwebLink*string|nullupdatedAt*stringdate-timecurl -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"}'{ "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"}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.
accountId*stringuuidapplication/json- body
attendees*array<>1 <= items <= 20start*stringdate-timeend*stringdate-timedurationMinutes?integer5 <= value <= 144030stepMinutes?integer5 <= value <= 144030timeZone?string1 <= length <= 64"UTC"workingHours?maxSuggestions?integer0 <= value <= 10010requireAll?booleanfalseincludeAccount?booleantrueOK
application/json- response
attendees*array<>suggestions*array<>complete*booleanunresolved*array<string>withheldReason*|nullcurl -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"}'{ "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"}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.
application/json- body
accountIds*array<>1 <= items <= 20mode?AvailabilityMode"all""all""any"attendees?array<>items <= 20[]start*stringdate-timeend*stringdate-timedurationMinutes?integer5 <= value <= 144030stepMinutes?integer5 <= value <= 144030timeZone?string1 <= length <= 64"UTC"workingHours?maxSuggestions?integer0 <= value <= 10010requireAll?booleanfalseOK
application/json- response
accounts*array<>attendees*array<>suggestions*array<>complete*booleanunresolved*array<string>withheldReason*|nullcurl -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"}'{ "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"}