Skip to content

Make one occurrence differ

POST
/events/{eventId}/exceptions
curl --request POST \
--url https://calendar.work.optidata.cloud/api/events/4167/exceptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "id": "4180", "inv_id": "4180-4179", "ms": 20140, "rev": 20140, "event_uid": "8f1c0a6e-3c4d-4c1a-9a2e-6a5b1d0f7c33", "calendar_id": "10", "recurrence_id": "2026-09-15T16:00:00-03:00", "title": "Team retro — quarter close", "datetime_start": "2026-09-15 16:00:00", "datetime_end": "2026-09-15 18:00:00", "is_all_day": false, "location": "Meeting room 1", "organizer": "jane.doe@acme.example" }'

Detaches a single occurrence of a recurring event from its series so it can carry its own title, description, location, guests or reminder while the rest of the series is untouched.

recurrence_id identifies which occurrence, and event_uid ties the exception back to the series. As with an update, id, inv_id, ms and rev come from the event you read.

To change only the time of one occurrence, use POST /events/{eventId}/exceptions/reschedule instead.

eventId
required
string

Id of the event, as returned in an event’s id.

Media typeapplication/json
object
title
required
string
datetime_start
required

When the event starts. Interpreted in the caller’s display time zone unless it carries an offset.

string
datetime_end
required

When the event ends. Must not be before datetime_start.

string
is_all_day
required

true for an event that spans whole days; send midnight-to-midnight bounds.

boolean
description
string | null
location
string | null
video_conference_url

Meeting room to attach to the event.

string | null format: uri
organizer
required

Address of the organizer.

string format: email
notification
One of:

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
time_unit

Unit of the lead time, for a timed event.

string
Allowed values: minutes hours days weeks
value

How many units before the start to fire the reminder.

integer
days_before

How many days before the event to fire it, for an all-day event.

integer
trigger_hour

Hour of the day the reminder fires, for an all-day event.

integer
<= 23
locale

Language for the invitation e-mails, e.g. pt_BR or en.

string | null
id
required

Id of the recurring event.

string
inv_id
required
string
ms
required
integer
rev
required
integer
event_uid
required

ICalendar UID of the series.

string
calendar_id
required
string
recurrence_id
required

Start of the occurrence that should differ.

string
attendees

Guest list for this occurrence.

Array<object>

Somebody to invite.

object
email
required
string format: email
name

Display name of the attendee. Mainly useful for somebody outside the tenant, who has no directory entry to take a name from.

string | null
type
One of:

user is somebody with an Optiwork account in the tenant, group a user group, and guest an address outside it.

string
Allowed values: user guest group
optiworkIdentifier

Optiwork identifier of the attendee, from GET /search/invitables. null for somebody outside the tenant.

string | null
should_notify_all_attendees
boolean | null
Examples
Exampleexception

One retro moves room and gets a longer slot

{
"id": "4180",
"inv_id": "4180-4179",
"ms": 20140,
"rev": 20140,
"event_uid": "8f1c0a6e-3c4d-4c1a-9a2e-6a5b1d0f7c33",
"calendar_id": "10",
"recurrence_id": "2026-09-15T16:00:00-03:00",
"title": "Team retro — quarter close",
"datetime_start": "2026-09-15 16:00:00",
"datetime_end": "2026-09-15 18:00:00",
"is_all_day": false,
"location": "Meeting room 1",
"organizer": "jane.doe@acme.example"
}

The event, with the new exception applied.

Media typeapplication/json
object
event
required

An event and its occurrences. The event itself carries the identifiers; everything about the schedule lives in instances.

object
id
string | null
uid

ICalendar UID. Unlike id, it survives the event being copied between calendars.

string | null
calendarId
required

Calendar the event lives in.

string
originalCalendarId
string | null
invId

Invitation id. Part of the concurrency triple you send back on an update.

string | null
ms

Modification sequence. Send it back unchanged on an update.

integer | null
rev

Revision. Send it back unchanged on an update.

integer | null
nextAlarm
One of:

The next reminder due for the event.

object
nextAlarmAt

When the reminder fires.

string | null
alarmInstStart

Start of the occurrence it belongs to.

string | null
invId
integer | null
instances
required
Array<object>

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
id
string | null
invId

Invitation id. Send it back when updating or rescheduling.

string | null
status
required

CONF confirmed, TENT tentative, CANC cancelled, NEED awaiting an answer.

string
Allowed values: CONF TENT CANC NEED
recurrenceId

Start of this occurrence, for a recurring event.

string | null
name

Title of the event.

string | null
location
string | null
start
required
string
end
required
string
isOrganizer
required

true when the caller owns the event.

boolean
isRecurring
required
boolean
isException
required

true when this occurrence was detached from its series.

boolean
isAllDay
required
boolean
videoConferenceUrl
string | null
description

Filled in on a single-event read; on a list, only when include_description was requested.

string | null
organizer
One of:

Who owns the event.

object
email
string | null
name
string | null
type
One of:

user is somebody with an Optiwork account in the tenant, group a user group, and guest an address outside it.

string
Allowed values: user guest group
avatarUrl
string | null
sentBy

Set when somebody sent the invitation for the organizer.

string | null
recurrenceRule
One of:

The repetition rule as stored. Mirrors the rule you send, in camelCase.

object
frequency
string
Allowed values: DAILY WEEKLY MONTHLY YEARLY
until
string | null
count
integer | null
interval
integer | null
byDay
Array<string> | null
byMonthDay
Array<integer> | null
byMonth
Array<integer> | null
bySetPos
Array<integer> | null
userParticipationStatus
One of:

How an attendee answered. NEEDS-ACTION means they have not answered yet.

string
Allowed values: NEEDS-ACTION ACCEPTED DECLINED TENTATIVE
originalTimezone

Time zone the event was created in, when it differs.

string | null
recurrenceBaseStart
string | null
recurrenceBaseEnd
string | null
attendees
required
Array<object>

Somebody invited to the event.

object
email
string | null
name
string | null
type
One of:

user is somebody with an Optiwork account in the tenant, group a user group, and guest an address outside it.

string
Allowed values: user guest group
avatarUrl
string | null
participationStatus
One of:

How an attendee answered. NEEDS-ACTION means they have not answered yet.

string
Allowed values: NEEDS-ACTION ACCEPTED DECLINED TENTATIVE
optiworkIdentifier
string | null
alarms
required
Array<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
description
string | null
related

Whether the offset is measured from the start or the end.

string | null
Allowed values: START END
isNegative
boolean
weeks
integer | null
days
integer | null
hours
integer | null
minutes
integer | null
seconds
integer | null
locale
string | null
participantsSummary

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
participantsCount
required

Number of participants of the occurrence: the organizer, when there is one, plus every attendee. 0 when it has none.

integer
participants
required

The first three participants, in the order above. Empty when the occurrence has none.

Array<object>
<= 3 items
object
name
required

The participant’s name or, when it has none, their email address. null when both are missing.

string | null
avatarUrl
required

The participant’s avatar, or null when there is none.

string | null
Example
{
"event": {
"id": "4167",
"calendarId": "10",
"instances": [
{
"status": "CONF",
"organizer": {
"type": "user"
},
"recurrenceRule": {
"frequency": "DAILY"
},
"userParticipationStatus": "NEEDS-ACTION",
"attendees": [
{
"type": "user",
"participationStatus": "NEEDS-ACTION"
}
],
"alarms": [
{
"related": "START"
}
],
"participantsSummary": {
"participantsCount": 5,
"participants": [
{
"name": "Jane Doe"
}
]
}
}
]
}
}

Missing, malformed or expired authentication key.

Media typeapplication/json

Authentication failures use an error key rather than message.

object
error
required
string
Examples
Examplemissing

No bearer token sent

{
"error": "JWT passport exception: Missing bearer token in request"
}

The caller is not the organizer of the event, or lacks write access to the calendar it lives in.

Media typeapplication/json

Failures raised by the calendar layer itself — a permission refusal, or a calendar or event that cannot be read. help is a hint for the end user and is often empty.

object
error
required

What went wrong.

string
status
required

Repeats the HTTP status code.

integer
help
required

Suggested next step, or an empty string.

string
Examples
ExamplenotOrganizer
{
"error": "Only the event organizer can change this event.",
"status": 403,
"help": "Ask the organizer to make this change for you."
}

The request body or query string failed validation.

Media typeapplication/json
object
message
required

The first validation message.

string
errors
required

Validation messages keyed by field name.

object
key
additional properties
Array<string>
Examples
Exampleinvalid
{
"message": "The event title field is required.",
"errors": {
"title": [
"The event title field is required."
]
}
}

Rate limit exceeded. Retry after the window resets.

Media typeapplication/json

Generic error envelope used by policy, binding and framework failures.

object
message
required

Human-readable description of the failure.

string
Examples
Examplethrottled
{
"message": "Too Many Attempts."
}