inboxes > calendar

Creates a one-off or recurring event on the inbox's calendar. Times are wall-clock values in timezone (the calendar's default time zone if omitted); the response also gives each boundary as a UTC instant in start_at and end_at.

calendar.event.created is sent once the event is stored, then calendar.event.starting and calendar.event.ending as each date begins and ends. With send_invites: true the inbox also emails an invitation to every attendee.

Pass client_id to make retries safe: repeating the request with the same client_id and body returns the original event with status 200 instead of 201, for as long as the event exists.

With send_invites: true, each attendee counts as one send against the organization, pod and inbox send limits, charged before the event is stored. An over-limit request returns 429 rate_limit_exceeded and creates nothing. A replay of an earlier create is not charged again.

The event's etag is the value to send in If-Match to make a later update or delete conditional. Requires the calendar_event_create permission.

Calendar is available in US production (api.agentmail.to) but not yet in EU production (api.agentmail.eu), which returns 403.

post/v0/inboxes/{inbox_id}/calendar/events

Request

  • Base URL
    https://api.agentmail.to
  • URL
    https://api.agentmail.to/v0/inboxes/{inbox_id}/calendar/events
  • Auth
    HTTP bearer

Path parameters

inbox_idstring required

The ID of the inbox.

Request body

client_idstring

Your idempotency key for this create. Retrying with the same client_id and the same body returns the original event with 200 instead of creating a second one, for as long as the event exists (404 once it has been deleted). Reusing it with a different body is a 409 idempotency_conflict.

titlestring required

Title of the event. 1 to 1,000 characters.

descriptionstring

Description of the event. At most 65,536 bytes.

locationstring

Location of the event. At most 1,024 characters.

metadataunknown
status'confirmed' | 'tentative' | 'cancelled'

Status of the event. A cancelled event or date stays readable but sends no calendar.event.starting or calendar.event.ending webhooks (cancelling a date that is already running still sends its calendar.event.ending). A date cancelled by deleting its dated ID is removed from the series instead, so reading it can return 404 or 410.

all_dayboolean

Set to true for an all-day event. Defaults to false.

startstring required

A local wall-clock time without an offset, interpreted in the event's timezone. Timed events use YYYY-MM-DDTHH:mm:ss (for example 2026-10-15T09:00:00). All-day events use YYYY-MM-DD. Years must be between 1900 and 9999.

endstring required

A local wall-clock time without an offset, interpreted in the event's timezone. Timed events use YYYY-MM-DDTHH:mm:ss (for example 2026-10-15T09:00:00). All-day events use YYYY-MM-DD. Years must be between 1900 and 9999.

timezonestring

IANA time zone name, for example America/New_York, Europe/London or UTC. Requests accept any capitalization and IANA aliases such as US/Eastern. The calendar stores and returns the canonical name, which for some zones is an older spelling: Asia/Kolkata is returned as Asia/Calcutta. Abbreviations such as PST and Windows names such as Pacific Standard Time are rejected.

duration_mode'nominal' | 'exact'

How the event's length is kept when a date crosses a daylight-saving change.

  • exact: the event lasts the same elapsed time. Default for one-off timed events.
  • nominal: the event keeps its wall-clock end time (a 09:00 to 10:00 meeting stays 09:00 to 10:00 local time). Default for recurring timed events.

All-day events are always nominal.

send_invitesboolean

When true, the inbox emails an invitation (iCalendar REQUEST) to every attendee. Defaults to false.

Response

Response with status 201

operation_idstring required

ID of the change this request made. The calendar.event.created, calendar.event.updated, calendar.event.deleted or calendar.event.responded webhook for the change carries the same value as its event_id, so you can match webhooks to your own requests.

Changes