Create an event
const url = 'https://calendar.work.optidata.cloud/api/events';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"calendar_ids":["10"],"title":"Sprint review","datetime_start":"2026-08-24 14:00:00","datetime_end":"2026-08-24 15:00:00","is_all_day":false,"location":"Meeting room 2","description":"Demo of the August milestone.","organizer":"jane.doe@acme.example","attendees":[{"email":"john.smith@acme.example","type":"user","optiworkIdentifier":"9ef34ce3-3b69-4762-b5e8-045499390ce6"},{"email":"contractor@partner.example","type":"guest","optiworkIdentifier":null}],"notification":{"time_unit":"minutes","value":15}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://calendar.work.optidata.cloud/api/events \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "calendar_ids": [ "10" ], "title": "Sprint review", "datetime_start": "2026-08-24 14:00:00", "datetime_end": "2026-08-24 15:00:00", "is_all_day": false, "location": "Meeting room 2", "description": "Demo of the August milestone.", "organizer": "jane.doe@acme.example", "attendees": [ { "email": "john.smith@acme.example", "type": "user", "optiworkIdentifier": "9ef34ce3-3b69-4762-b5e8-045499390ce6" }, { "email": "contractor@partner.example", "type": "guest", "optiworkIdentifier": null } ], "notification": { "time_unit": "minutes", "value": 15 } }'Creates an event and invites its attendees.
calendar_ids accepts more than one calendar. The event is written to all
of them in a single operation, which is how a room or another shared
resource is booked alongside the organizer’s own calendar. Invitations
are sent only for the first calendar in the list, so put the organizer’s
calendar first. The response returns that first event as event and the
whole batch as events.
Reminders are expressed in notification, and the two allowed shapes
depend on is_all_day:
- timed event (
is_all_day: false) —time_unitplusvalue, meaning “this long before the start”; - all-day event (
is_all_day: true) —days_beforeplustrigger_hour, meaning “at this hour of the day, this many days before”.
Omit notification entirely for an event with no reminder.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
When the event starts. Interpreted in the caller’s display time zone unless it carries an offset.
When the event ends. Must not be before datetime_start.
true for an event that spans whole days; send midnight-to-midnight
bounds.
Meeting room to attach to the event.
Address of the organizer.
A single reminder. Send time_unit and value for a timed event, or
days_before and trigger_hour for an all-day one. Omit the object
entirely for an event with no reminder.
object
Unit of the lead time, for a timed event.
How many units before the start to fire the reminder.
How many days before the event to fire it, for an all-day event.
Hour of the day the reminder fires, for an all-day event.
Language for the invitation e-mails, e.g. pt_BR or en.
Calendars to create the event in. Invitations are sent only for the
first one, so put the organizer’s calendar first. The legacy
single-value calendar_id is still accepted and is treated as a
one-element list.
People to invite.
Somebody to invite.
object
Display name of the attendee. Mainly useful for somebody outside the tenant, who has no directory entry to take a name from.
Optiwork identifier of the attendee, from
GET /search/invitables. null for
somebody outside the tenant.
How an event repeats, in iCalendar terms. frequency is the only required
part; count and until are two ways of ending the series, and the by_*
fields narrow which occurrences the frequency produces.
When a by_* field is omitted, it is inferred from datetime_start —
a weekly series repeats on the weekday it starts on, a monthly one on the
same day of the month.
object
How often the event repeats.
Repeat every N periods: 2 with WEEKLY means fortnightly.
End the series after this many occurrences.
End the series at this moment.
Weekdays the event falls on.
Days of the month, 1–31.
Months, 1–12.
Which occurrence within the period: 1–4 for first through fourth,
-1 for last. Combine with by_day for “the last Friday of the
month”.
Examples
A one-hour meeting with two guests
{ "calendar_ids": [ "10" ], "title": "Sprint review", "datetime_start": "2026-08-24 14:00:00", "datetime_end": "2026-08-24 15:00:00", "is_all_day": false, "location": "Meeting room 2", "description": "Demo of the August milestone.", "organizer": "jane.doe@acme.example", "attendees": [ { "email": "john.smith@acme.example", "type": "user", "optiworkIdentifier": "9ef34ce3-3b69-4762-b5e8-045499390ce6" }, { "email": "contractor@partner.example", "type": "guest", "optiworkIdentifier": null } ], "notification": { "time_unit": "minutes", "value": 15 }}Every second Tuesday until the end of the year
{ "calendar_ids": [ "10" ], "title": "Team retro", "datetime_start": "2026-09-01 16:00:00", "datetime_end": "2026-09-01 17:00:00", "is_all_day": false, "organizer": "jane.doe@acme.example", "recurrence_rule": { "frequency": "WEEKLY", "interval": 2, "by_day": [ "TU" ], "until": "2026-12-31 23:59:59" }}An all-day event with a reminder the day before
{ "calendar_ids": [ "10" ], "title": "Company offsite", "datetime_start": "2026-09-10 00:00:00", "datetime_end": "2026-09-11 00:00:00", "is_all_day": true, "organizer": "jane.doe@acme.example", "notification": { "days_before": 1, "trigger_hour": 9 }}Responses
Section titled “ Responses ”The created event. event is the copy in the first calendar — the one
invitations were sent for — and events holds every copy created.
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.
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
{ "event": { "id": "4171", "uid": "8f1c0a6e-3c4d-4c1a-9a2e-6a5b1d0f7c33", "calendarId": "10", "invId": "4171-4170", "ms": 20130, "rev": 20130, "nextAlarm": null, "instances": [ { "id": "4171", "invId": "4171-4170", "status": "CONF", "name": "Sprint review", "start": "2026-08-24T14:00:00-03:00", "end": "2026-08-24T15:00:00-03:00", "isOrganizer": true, "isRecurring": false, "isException": false, "isAllDay": false, "userParticipationStatus": "ACCEPTED", "attendees": [], "alarms": [] } ] }, "events": [ { "id": "4171", "calendarId": "10", "invId": "4171-4170", "instances": [ { "id": "4171", "status": "CONF", "name": "Sprint review", "start": "2026-08-24T14:00:00-03:00", "end": "2026-08-24T15:00:00-03:00", "isOrganizer": true, "isRecurring": false, "isException": false, "isAllDay": false, "attendees": [], "alarms": [] } ] } ]}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 request body or query string failed validation.
object
The first validation message.
Validation messages keyed by field name.
object
Examples
{ "message": "The event title field is required.", "errors": { "title": [ "The event title field is required." ] }}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."}