List events
const url = 'https://calendar.work.optidata.cloud/api/events?datetime_start=2026-08-01%2000%3A00%3A00&datetime_end=2026-08-31%2023%3A59%3A59&organizer=any&name=Sprint&event_id=4167&event_uid=de373eee-9440-4420-a53b-1be5ccd4eb18&include_description=false&include_participants_summary=false&limit=1000';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://calendar.work.optidata.cloud/api/events?datetime_start=2026-08-01%2000%3A00%3A00&datetime_end=2026-08-31%2023%3A59%3A59&organizer=any&name=Sprint&event_id=4167&event_uid=de373eee-9440-4420-a53b-1be5ccd4eb18&include_description=false&include_participants_summary=false&limit=1000' \ --header 'Authorization: Bearer <token>'Events visible to the authenticated user, across every calendar they can
see. Narrow the result with the query parameters below; a call with no
filters returns everything up to limit, which is rarely what you want.
For a month view, pass datetime_start and datetime_end. A recurring
event inside the window is returned once, with one entry in instances
per occurrence that falls inside it.
Search results carry a summary of each event; the full description is
omitted unless you ask for include_description=true, which costs an
extra round trip on the server.
Search results also carry no attendees (attendees is always empty on
a list). For an event card that shows who takes part, pass
include_participants_summary=true: each occurrence then carries a
participantsSummary with the number of participants and the first
three of them (name and avatar). It is read in the same extra round
trip as include_description, so asking for both costs one round trip.
To split the events by who organizes them, pass organizer:
is_organizer keeps only the occurrences you organize and
is_not_organizer only the ones you do not. The filter is checked per
occurrence, so it needs both datetime_start and datetime_end: a
recurring event comes back with only its matching occurrences in
instances, and an event left without any is dropped from the
response. In a calendar shared with you, the event’s organizer is
compared with you, not with the calendar owner, so an event a delegate
creates on the owner’s behalf counts as organized by the owner, not by
you. limit applies to the events left after the filter.
With an active filter, only the first max(limit, 1000) events of the
range are checked, so a dense calendar can return fewer matching events
than exist, or none, even when more match past that cap. Narrow the
range for dense calendars.
Every query parameter is validated: an unknown organizer value, a
missing date range with an active organizer filter, an invalid
limit, a malformed event_id, an unrecognized value of
include_description or include_participants_summary, an invalid
date or an end before the start returns 422. Any query parameter not
listed below is ignored.
Authorizations
Section titled “Authorizations”Parameters
Section titled “ Parameters ”Query Parameters
Section titled “Query Parameters”Only return occurrences that end at or after this moment. Must
contain a calendar date (ISO 8601 or Y-m-d H:i:s); text without
one, such as today, returns 422. Required when organizer is
is_organizer or is_not_organizer.
Only return occurrences that start at or before this moment. Must
contain a calendar date (ISO 8601 or Y-m-d H:i:s); text without
one, such as today, returns 422. Must be at or after
datetime_start when both are sent. Required when organizer is
is_organizer or is_not_organizer.
Filter the occurrences by your role as organizer:
any(default): no filter;is_organizer: only the occurrences you organize;is_not_organizer: only the occurrences you do not organize.
Values are case-sensitive; any other value, an empty value or an array
returns 422. is_organizer and is_not_organizer require
datetime_start and datetime_end.
Match events whose title starts with this text. The text is matched
literally: quotes, parentheses and words such as OR are part of the
title searched, not search operators.
Restrict the search to these calendars. Repeat the parameter once per
calendar (calendar_ids[]=10&calendar_ids[]=454). Omit it to search
every calendar the caller can see. Each id must be an integer, and the
parameter must be sent as a list (with the brackets); otherwise the
call returns 422.
Return only the event with this id: digits (4167) or, for an event
of a calendar shared with you, the owner’s account id, a colon and
the digits (0b9a1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d:4167). An empty
value (event_id=) is the same as omitting the parameter; any other
value, or an array, returns 422.
Return only the event with this iCalendar UID — the identifier that stays stable when an event is copied between calendars.
Fill in each event’s full description. Off by default. Accepts true,
false, 1, 0, yes, no, on and off, in any letter case. An
empty value (include_description=) is the same as omitting the
parameter (off); any other value, or an array, returns 422.
Add a participantsSummary to each occurrence in instances: the
number of participants and the first three of them, for an event card.
Off by default; without it the response is unchanged and carries no
participantsSummary. See ParticipantsSummary for how the
participants are counted and ordered.
The participants are read from the event details, in the same extra
round trip on the server as include_description (one round trip
when both are on).
Accepts true, false, 1, 0, yes, no, on and off, in any
letter case. An empty value (include_participants_summary=) is the
same as omitting the parameter (off); any other value, or an array,
returns 422.
Maximum number of events to return. Must be a positive integer; 0,
a negative or a non-integer value returns 422. With an active
organizer filter, it applies to the events left after the filter.
Responses
Section titled “ Responses ”Matching events.
object
An event and its occurrences. The event itself carries the identifiers;
everything about the schedule lives in instances.
object
ICalendar UID. Unlike id, it survives the event being copied between
calendars.
Calendar the event lives in.
Invitation id. Part of the concurrency triple you send back on an update.
Modification sequence. Send it back unchanged on an update.
Revision. Send it back unchanged on an update.
One occurrence of an event. A one-off event has exactly one; a recurring event has one per occurrence inside the window you asked for.
object
Invitation id. Send it back when updating or rescheduling.
CONF confirmed, TENT tentative, CANC cancelled, NEED awaiting
an answer.
Start of this occurrence, for a recurring event.
Title of the event.
true when the caller owns the event.
true when this occurrence was detached from its series.
Filled in on a single-event read; on a list, only when
include_description was requested.
Who owns the event.
Time zone the event was created in, when it differs.
Somebody invited to the event.
object
A reminder, expressed as an offset from the event. isNegative: true means
the reminder fires before the moment named by related; the unit fields
that do not apply are 0 or null.
object
Whether the offset is measured from the start or the end.
Who takes part in one occurrence, summarized for an event card. Present
only on a list (GET /events) called with
include_participants_summary=true; absent otherwise.
The participants are listed as the event details show them: the organizer first, when the occurrence has one, then the attendees in invitation order. The organizer is not looked up among the attendees, so an organizer who is also listed as an attendee counts twice. An exception occurrence is summarized from its own participants.
Even with the flag on, an occurrence can lack participantsSummary
when its participants could not be read, for instance when the event
was deleted while the list was being built. Read a missing
participantsSummary as unknown, not as zero participants.
object
Number of participants of the occurrence: the organizer, when there
is one, plus every attendee. 0 when it has none.
The first three participants, in the order above. Empty when the occurrence has none.
object
The participant’s name or, when it has none, their email
address. null when both are missing.
The participant’s avatar, or null when there is none.
Examples
{ "events": [ { "id": "4167", "uid": "de373eee-9440-4420-a53b-1be5ccd4eb18", "calendarId": "10", "nextAlarm": null, "invId": "4167-4166", "ms": 20125, "rev": 20120, "originalCalendarId": null, "instances": [ { "id": "4167", "invId": "4167-4166", "status": "CONF", "recurrenceId": null, "name": "Sprint review", "location": "Meeting room 2", "start": "2026-08-24T14:00:00-03:00", "end": "2026-08-24T15:00:00-03:00", "isOrganizer": true, "isRecurring": false, "isException": false, "isAllDay": false, "videoConferenceUrl": null, "description": null, "organizer": { "email": "jane.doe@acme.example", "name": "Jane Doe", "type": "user", "avatarUrl": null, "sentBy": null }, "recurrenceRule": null, "userParticipationStatus": "ACCEPTED", "originalTimezone": null, "recurrenceBaseStart": null, "recurrenceBaseEnd": null, "attendees": [], "alarms": [], "locale": null } ] } ]}With include_participants_summary=true
An event organized by Jane Doe with four attendees: five participants, of which the first three are listed. The third has no name, so the email address is shown instead.
{ "events": [ { "id": "4167", "uid": "de373eee-9440-4420-a53b-1be5ccd4eb18", "calendarId": "10", "nextAlarm": null, "invId": "4167-4166", "ms": 20125, "rev": 20120, "originalCalendarId": null, "instances": [ { "id": "4167", "invId": "4167-4166", "status": "CONF", "recurrenceId": null, "name": "Sprint review", "location": "Meeting room 2", "start": "2026-08-24T14:00:00-03:00", "end": "2026-08-24T15:00:00-03:00", "isOrganizer": true, "isRecurring": false, "isException": false, "isAllDay": false, "videoConferenceUrl": null, "description": null, "organizer": { "email": "jane.doe@acme.example", "name": "Jane Doe", "type": "user", "avatarUrl": null, "sentBy": null }, "recurrenceRule": null, "userParticipationStatus": "ACCEPTED", "originalTimezone": null, "recurrenceBaseStart": null, "recurrenceBaseEnd": null, "attendees": [], "alarms": [], "locale": null, "participantsSummary": { "participantsCount": 5, "participants": [ { "name": "Jane Doe", "avatarUrl": null }, { "name": "John Roe", "avatarUrl": "https://cdn.acme.example/avatars/john-roe.png" }, { "name": "guest@partner.example", "avatarUrl": null } ] } } ] } ]}Missing, malformed or expired authentication key.
Authentication failures use an error key rather than message.
object
Examples
No bearer token sent
{ "error": "JWT passport exception: Missing bearer token in request"}The query string failed validation.
object
The first validation message.
Validation messages keyed by field name.
object
Examples
Unknown organizer value (e.g. abc, true, IS_ORGANIZER)
{ "message": "The selected organizer is invalid.", "errors": { "organizer": [ "The selected organizer is invalid." ] }}Empty organizer value, or an array (organizer[]=...)
{ "message": "The organizer must be a string. (and 1 more error)", "errors": { "organizer": [ "The organizer must be a string.", "The selected organizer is invalid." ] }}Active organizer filter without the date range
{ "message": "The start date and time field is required. (and 1 more error)", "errors": { "datetime_start": [ "The start date and time field is required." ], "datetime_end": [ "The end date and time field is required." ] }}Limit below 1 (e.g. 0, -5)
{ "message": "The limit must be at least 1.", "errors": { "limit": [ "The limit must be at least 1." ] }}Non-integer limit (e.g. abc, 1.5)
{ "message": "The limit must be an integer.", "errors": { "limit": [ "The limit must be an integer." ] }}Malformed event_id (e.g. abc-123, 1*, a quote)
{ "message": "The event format is invalid.", "errors": { "event_id": [ "The event format is invalid." ] }}Invalid or relative date (e.g. today)
{ "message": "The start date and time is not a valid date.", "errors": { "datetime_start": [ "The start date and time is not a valid date." ] }}datetime_end before datetime_start
{ "message": "The end date and time must be a date after or equal to start date and time.", "errors": { "datetime_end": [ "The end date and time must be a date after or equal to start date and time." ] }}Unrecognized include_participants_summary value (e.g. maybe), or an array
{ "message": "The include participants summary field must be true or false.", "errors": { "include_participants_summary": [ "The include participants summary field must be true or false." ] }}Rate limit exceeded. Retry after the window resets.
Generic error envelope used by policy, binding and framework failures.
object
Human-readable description of the failure.
Examples
{ "message": "Too Many Attempts."}