---
title: "Calendar"
description: "Every operation in this group: what it accepts, what it returns and the errors it can answer with."
url: "https://nextmail.sh/docs/api/reference/calendar"
area: "API"
category: "Reference"
---

# Calendar

Every operation in this group: what it accepts, what it returns and the errors it can answer with.

## Operations

Events and invitations, as the Calendar page of the app shows them: list a window, read an event or the one a thread carries, put events on the calendar and change them, call off a meeting, and answer an invitation. A change that invites, updates or cancels attendees, and every answer, goes out by email, so it also needs `emails:send`.

### `GET /calendar/events`

List occurrences in a window

`from` and `to` are REQUIRED. Occurrences are expanded from recurrence rules, so a calendar has no meaningful unbounded listing. A default window would turn an infinite series into a question with no answer. At most a year apart.

Lists your own events: the ones you made and the ones an address of yours organises or attends. For the workspace owner and their keys, an address counts as theirs unless it was given to a teammate. Set `includeTeam` to true to add the rest of the workspace, apart from events somebody marked private. A member and a narrowed key always get their own view, whatever `includeTeam` says.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Query parameters**

- `from` (`string`, required, format `date-time`): Start of the window.
- `to` (`string`, required, format `date-time`): End of the window, after `from` and at most 366 days later.
- `timezone` (`string`, required): IANA zone. Decides what an all-day event means.
- `includeTeam` (`boolean`, default `false`): Adds the events of the rest of the workspace, apart from the ones marked private. Only the workspace owner and their keys see more with it.
- `q` (`string`, up to 200 characters): Words to look for in the title, the place and the organiser. Only events that hold every word come back, so search a long window, at most a year, to find an event by name.
- `limit` (`integer`, at least 1, at most 100, default `25`): Rows per page, 1 to 100.
- `cursor` (`string`): The previous page's `nextCursor`, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400 `invalid_cursor`.

**Returns**

- `200` `CalendarOccurrenceList`: A page of occurrences, sorted by start and then by event id, with `hasMore` and `nextCursor`. Send the same `from`, `to`, `timezone` and `q` with every `cursor`. Nothing in the window is dropped: a series repeats at most once a day, so it gives at most one occurrence per day of the window, and every one is reachable through the pages. The cursor holds the start and event id of the last row, so an event deleted or moved between pages never breaks the walk.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.listEvents()`](https://nextmail.sh/docs/sdk/reference/calendar#listEvents), [`nextmail.calendar.listAllEvents()`](https://nextmail.sh/docs/sdk/reference/calendar#listAllEvents), [`nextmail.calendar.iterateEvents()`](https://nextmail.sh/docs/sdk/reference/calendar#iterateEvents); Python [`calendar.list_events()`](https://nextmail.sh/docs/python/reference/calendar#listEvents), [`calendar.list_all_events()`](https://nextmail.sh/docs/python/reference/calendar#listAllEvents), [`calendar.iterate_events()`](https://nextmail.sh/docs/python/reference/calendar#iterateEvents); Ruby [`calendar.list_events`](https://nextmail.sh/docs/ruby/reference/calendar#listEvents), [`calendar.list_all_events`](https://nextmail.sh/docs/ruby/reference/calendar#listAllEvents), [`calendar.iterate_events`](https://nextmail.sh/docs/ruby/reference/calendar#iterateEvents); PHP [`calendar->listEvents`](https://nextmail.sh/docs/php/reference/calendar#listEvents), [`calendar->listAllEvents`](https://nextmail.sh/docs/php/reference/calendar#listAllEvents), [`calendar->iterateEvents`](https://nextmail.sh/docs/php/reference/calendar#iterateEvents); Go [`Calendar.ListEvents`](https://nextmail.sh/docs/go/reference/calendar#listEvents), [`Calendar.ListAllEvents`](https://nextmail.sh/docs/go/reference/calendar#listAllEvents), [`Calendar.IterateEvents`](https://nextmail.sh/docs/go/reference/calendar#iterateEvents); Java [`calendar().listEvents`](https://nextmail.sh/docs/java/reference/calendar#listEvents), [`calendar().listAllEvents`](https://nextmail.sh/docs/java/reference/calendar#listAllEvents), [`calendar().iterateEvents`](https://nextmail.sh/docs/java/reference/calendar#iterateEvents); C# [`Calendar.ListEventsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#listEvents), [`Calendar.ListAllEventsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#listAllEvents), [`Calendar.IterateEventsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#iterateEvents); CLI [`nextmail calendar list-events`](https://nextmail.sh/docs/cli/reference/calendar#calendar-list-events); MCP [`listCalendarEvents`](https://nextmail.sh/docs/mcp/tools/calendar#listCalendarEvents).

### `POST /calendar/events`

Create an event

Puts an event on the calendar, as New event on the Calendar page of the app does. `start` and `end` are ISO 8601 with a zone, and `timezone` is the IANA zone the event belongs to, UTC unless you say. `recurrence` takes an RRULE such as `FREQ=WEEKLY;BYDAY=MO`, and `reminders` the minutes before the start.

With attendees, an invitation goes to each of them from the address in `from`, which has to be one the key or app may send as, so the call also needs `emails:send`. `sendInvites: false` keeps the change to your own calendar.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Request body**

- `summary` (`string`, required, 1 to 255 characters): The title, 1 to 255 characters.
- `description` (`string`, up to 8000 characters): Notes about the event, up to 8,000 characters.
- `location` (`string`, up to 255 characters): Where it is: a room, an address or a link.
- `url` (`string`, up to 2000 characters, format `uri`): A link that belongs to the event.
- `meetingUrl` (`string`, up to 2000 characters): A link to the video call, such as a Zoom, Meet or Teams address. It goes into the invitation, so guests see a Join button in their calendar too. Send an empty string to take it off.
- `start` (`string`, required, format `date-time`): When it starts, a `Date` or ISO 8601 with a zone.
- `end` (`string`, required, format `date-time`): When it ends, after `start` and at most two years later.
- `allDay` (`boolean`): Whether it fills whole days. `start` and `end` then mark the days.
- `timezone` (`string`, 1 to 64 characters): The IANA zone the event belongs to, `UTC` unless you say.
- `recurrence` (`string`, up to 512 characters): An RRULE such as `FREQ=WEEKLY;BYDAY=MO` when it repeats.
- `attendees` (`object[]`, up to 200 items): Up to 200 people to invite, each `{ email, name?, optional? }`.
  - `email` (`string`, required, up to 320 characters, format `email`)
  - `name` (`string`, up to 128 characters)
  - `optional` (`boolean`)
- `reminders` (`object[]`, up to 5 items): Up to five reminders, each `{ minutesBefore, action? }`.
  - `minutesBefore` (`integer`, required, at least 0, at most 40320)
  - `action` (`string`, one of `"DISPLAY"`, `"EMAIL"`, `"AUDIO"`)
- `transparency` (`string`, one of `"OPAQUE"`, `"TRANSPARENT"`): `OPAQUE` shows you busy and `TRANSPARENT` free.
- `visibility` (`string`, one of `"PUBLIC"`, `"PRIVATE"`, `"CONFIDENTIAL"`): `PUBLIC`, `PRIVATE` or `CONFIDENTIAL`.
- `sendInvites` (`boolean`): False keeps the change to your own calendar, and sends nothing.
- `from` (`string`, up to 320 characters): The address the invitations come from. It has to be one the key may send as.

**Returns**

- `201` `CalendarEvent`: The event, with its attendees.

**Errors**

- `403`: `from_address_forbidden`: the key or app may not send as `from`. `insufficient_scope` when invitations would go out and `emails:send` is missing.
- The errors every operation can return: `400`, `401`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.createEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#createEvent); Python [`calendar.create_event()`](https://nextmail.sh/docs/python/reference/calendar#createEvent); Ruby [`calendar.create_event`](https://nextmail.sh/docs/ruby/reference/calendar#createEvent); PHP [`calendar->createEvent`](https://nextmail.sh/docs/php/reference/calendar#createEvent); Go [`Calendar.CreateEvent`](https://nextmail.sh/docs/go/reference/calendar#createEvent); Java [`calendar().createEvent`](https://nextmail.sh/docs/java/reference/calendar#createEvent); C# [`Calendar.CreateEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#createEvent); CLI [`nextmail calendar create-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-create-event); MCP [`createCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#createCalendarEvent).

### `GET /calendar/events/{id}`

Retrieve an event

The event with its attendees and their responses. `rawIcs` is omitted. Everything understood in it is already structured here, and `/ics` serves the document.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Path parameters**

- `id` (`string`, required): Event id, the `eventId` of an occurrence, such as `cal_` followed by 24 hex characters.

**Returns**

- `200` `CalendarEvent`: The event.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.getEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#getEvent); Python [`calendar.get_event()`](https://nextmail.sh/docs/python/reference/calendar#getEvent); Ruby [`calendar.get_event`](https://nextmail.sh/docs/ruby/reference/calendar#getEvent); PHP [`calendar->getEvent`](https://nextmail.sh/docs/php/reference/calendar#getEvent); Go [`Calendar.GetEvent`](https://nextmail.sh/docs/go/reference/calendar#getEvent); Java [`calendar().getEvent`](https://nextmail.sh/docs/java/reference/calendar#getEvent); C# [`Calendar.GetEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#getEvent); CLI [`nextmail calendar get-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-get-event); MCP [`getCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#getCalendarEvent).

### `PATCH /calendar/events/{id}`

Change an event

Changes an event you organise. A field left out keeps its value, and `attendees` replaces the whole list. Everyone invited gets the updated invitation.

For a repeating event, `scope` says which dates change, as the app asks when you edit one date: `occurrence` changes only the date that starts at `occurrenceStart`, `following` that date and every one after it (they become a new series, and the old one ends the day before), and `series` all of them, with a new `start` or `end` moving every date by the same amount.

With attendees, an invitation goes to each of them from the address in `from`, which has to be one the key or app may send as, so the call also needs `emails:send`. `sendInvites: false` keeps the change to your own calendar.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The event id from `GET /calendar/events`.

**Request body**

- `summary` (`string`, 1 to 255 characters): The title, 1 to 255 characters.
- `description` (`string`, up to 8000 characters): Notes about the event, up to 8,000 characters.
- `location` (`string`, up to 255 characters): Where it is: a room, an address or a link.
- `url` (`string`, up to 2000 characters, format `uri`): A link that belongs to the event.
- `meetingUrl` (`string`, up to 2000 characters): A link to the video call, such as a Zoom, Meet or Teams address. It goes into the invitation, so guests see a Join button in their calendar too. Send an empty string to take it off.
- `start` (`string`, format `date-time`): When it starts, a `Date` or ISO 8601 with a zone.
- `end` (`string`, format `date-time`): When it ends, after `start` and at most two years later.
- `allDay` (`boolean`): Whether it fills whole days. `start` and `end` then mark the days.
- `timezone` (`string`, 1 to 64 characters): The IANA zone the event belongs to, `UTC` unless you say.
- `recurrence` (`string`, up to 512 characters): An RRULE such as `FREQ=WEEKLY;BYDAY=MO` when it repeats.
- `attendees` (`object[]`, up to 200 items): Up to 200 people to invite, each `{ email, name?, optional? }`. It replaces the whole list.
  - `email` (`string`, required, up to 320 characters, format `email`)
  - `name` (`string`, up to 128 characters)
  - `optional` (`boolean`)
- `reminders` (`object[]`, up to 5 items): Up to five reminders, each `{ minutesBefore, action? }`.
  - `minutesBefore` (`integer`, required, at least 0, at most 40320)
  - `action` (`string`, one of `"DISPLAY"`, `"EMAIL"`, `"AUDIO"`)
- `transparency` (`string`, one of `"OPAQUE"`, `"TRANSPARENT"`): `OPAQUE` shows you busy and `TRANSPARENT` free.
- `visibility` (`string`, one of `"PUBLIC"`, `"PRIVATE"`, `"CONFIDENTIAL"`): `PUBLIC`, `PRIVATE` or `CONFIDENTIAL`.
- `sendInvites` (`boolean`): False keeps the change to your own calendar, and sends nothing.
- `from` (`string`, up to 320 characters): The address the invitations come from. It has to be one the key may send as.
- `scope` (`string`, one of `"occurrence"`, `"following"`, `"series"`): Which dates the change reaches when the event repeats: `occurrence` for the one date in `occurrenceStart`, `following` for that date and every one after it, or `series` for all of them. Left out, the change reaches the event or date the id names.
- `occurrenceStart` (`string`, format `date-time`): The start of the date you mean, as it appears in the list of events. Needed with `occurrence` and `following`.

**Returns**

- `200` `CalendarEvent`: The event as it stands now.

**Errors**

- `403`: `not_organizer`: the event was organised by somebody else, so you can only answer it. `from_address_forbidden`: the key or app may not send as `from`.
- `409`: `event_cancelled`: the meeting was called off.
- The errors every operation can return: `400`, `401`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.updateEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#updateEvent); Python [`calendar.update_event()`](https://nextmail.sh/docs/python/reference/calendar#updateEvent); Ruby [`calendar.update_event`](https://nextmail.sh/docs/ruby/reference/calendar#updateEvent); PHP [`calendar->updateEvent`](https://nextmail.sh/docs/php/reference/calendar#updateEvent); Go [`Calendar.UpdateEvent`](https://nextmail.sh/docs/go/reference/calendar#updateEvent); Java [`calendar().updateEvent`](https://nextmail.sh/docs/java/reference/calendar#updateEvent); C# [`Calendar.UpdateEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#updateEvent); CLI [`nextmail calendar update-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-update-event); MCP [`updateCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#updateCalendarEvent).

### `DELETE /calendar/events/{id}`

Remove an event

Removes an event from the calendar for good, as Remove does in the app. Nobody else is told: to call off a meeting with others in it, use `POST /calendar/events/{id}/cancel`. For a repeating event, `scope` and `occurrenceStart` remove one date or that date and every one after it.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The event id from `GET /calendar/events`.

**Query parameters**

- `scope` (`string`, one of `"occurrence"`, `"following"`, `"series"`): Which dates the change reaches when the event repeats: `occurrence` for the one date in `occurrenceStart`, `following` for that date and every one after it, or `series` for all of them. Left out, the change reaches the event or date the id names.
- `occurrenceStart` (`string`, format `date-time`): The start of the date you mean, as it appears in the list of events. Needed with `occurrence` and `following`.

**Returns**

- `200` `DeletedCalendarEvent`: The event is gone.

**Errors**

- `403`: `not_organizer`: the event was organised by somebody else.
- The errors every operation can return: `400`, `401`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.deleteEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#deleteEvent); Python [`calendar.delete_event()`](https://nextmail.sh/docs/python/reference/calendar#deleteEvent); Ruby [`calendar.delete_event`](https://nextmail.sh/docs/ruby/reference/calendar#deleteEvent); PHP [`calendar->deleteEvent`](https://nextmail.sh/docs/php/reference/calendar#deleteEvent); Go [`Calendar.DeleteEvent`](https://nextmail.sh/docs/go/reference/calendar#deleteEvent); Java [`calendar().deleteEvent`](https://nextmail.sh/docs/java/reference/calendar#deleteEvent); C# [`Calendar.DeleteEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#deleteEvent); CLI [`nextmail calendar delete-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-delete-event); MCP [`deleteCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#deleteCalendarEvent).

### `GET /calendar/events/{id}/ics`

The event as an .ics document

Served as `text/calendar` with NO `METHOD` parameter. A METHOD makes a document actionable (a client seeing `method=REQUEST` draws accept/decline and can reply to the organiser), and this endpoint has no authority to invite anybody on the workspace behalf. It states what the event currently is.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Path parameters**

- `id` (`string`, required): Event id, the `eventId` of an occurrence.

**Returns**

- `200` `string` (`text/calendar`): An iCalendar document.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.getEventIcs()`](https://nextmail.sh/docs/sdk/reference/calendar#getEventIcs); Python [`calendar.get_event_ics()`](https://nextmail.sh/docs/python/reference/calendar#getEventIcs); Ruby [`calendar.get_event_ics`](https://nextmail.sh/docs/ruby/reference/calendar#getEventIcs); PHP [`calendar->getEventIcs`](https://nextmail.sh/docs/php/reference/calendar#getEventIcs); Go [`Calendar.GetEventIcs`](https://nextmail.sh/docs/go/reference/calendar#getEventIcs); Java [`calendar().getEventIcs`](https://nextmail.sh/docs/java/reference/calendar#getEventIcs); C# [`Calendar.GetEventIcsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#getEventIcs); CLI [`nextmail calendar get-event-ics`](https://nextmail.sh/docs/cli/reference/calendar#calendar-get-event-ics).

### `POST /calendar/events/{id}/cancel`

Cancel a meeting

Calls off a meeting you organise, as Cancel meeting does in the app. It stays on the calendar with `status` `CANCELLED`, and everyone invited is told it is off, from the address in `from`, so a meeting with attendees also needs `emails:send`. For a repeating meeting, `scope` and `occurrenceStart` call off one date, or that date and every one after it, and guests get the matching update. The body is optional.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The event id from `GET /calendar/events`.

**Request body**

- `from` (`string`, up to 320 characters): The address the cancellation comes from. It has to be one the key may send as.
- `notifyGuests` (`boolean`)
- `scope` (`string`, one of `"occurrence"`, `"following"`, `"series"`): Which dates the change reaches when the event repeats: `occurrence` for the one date in `occurrenceStart`, `following` for that date and every one after it, or `series` for all of them. Left out, the change reaches the event or date the id names.
- `occurrenceStart` (`string`, format `date-time`): The start of the date you mean, as it appears in the list of events. Needed with `occurrence` and `following`.

**Returns**

- `200` `CalendarEvent`: The event, cancelled.

**Errors**

- `403`: `not_organizer`: the event was organised by somebody else. `from_address_forbidden`: the key or app may not send as `from`.
- The errors every operation can return: `400`, `401`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.cancelEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#cancelEvent); Python [`calendar.cancel_event()`](https://nextmail.sh/docs/python/reference/calendar#cancelEvent); Ruby [`calendar.cancel_event`](https://nextmail.sh/docs/ruby/reference/calendar#cancelEvent); PHP [`calendar->cancelEvent`](https://nextmail.sh/docs/php/reference/calendar#cancelEvent); Go [`Calendar.CancelEvent`](https://nextmail.sh/docs/go/reference/calendar#cancelEvent); Java [`calendar().cancelEvent`](https://nextmail.sh/docs/java/reference/calendar#cancelEvent); C# [`Calendar.CancelEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#cancelEvent); CLI [`nextmail calendar cancel-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-cancel-event); MCP [`cancelCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#cancelCalendarEvent).

### `POST /calendar/events/{id}/respond`

Answer an invitation

Accepts, declines or tentatively accepts an invitation, as the buttons of an invitation in the app do. The answer goes to the organiser by email from the invited address the key or app may send as, or from `respondingAs` when the invitation went to more than one of yours. Send `proposedStart` and `proposedEnd` together to propose a new time with your answer, as Propose a new time does in the app: the organiser gets a counter-proposal and decides.

Requires the `calendar:write` and `emails:send` scopes.

- Scopes: `calendar:write`, `emails:send`.

**Path parameters**

- `id` (`string`, required): The event id from `GET /calendar/events`.

**Request body**

- `response` (`string`, required, one of `"ACCEPTED"`, `"DECLINED"`, `"TENTATIVE"`): `ACCEPTED`, `DECLINED` or `TENTATIVE`.
- `respondingAs` (`string`, up to 320 characters): Which of your invited addresses answers, when there is more than one.
- `proposedStart` (`string`, format `date-time`): A new start to propose with your answer, sent together with `proposedEnd`.
- `proposedEnd` (`string`, format `date-time`): The end of the proposed time.
- `notifyGuests` (`boolean`)

**Returns**

- `200` `CalendarEvent`: The event, with your answer.

**Errors**

- `403`: `not_invited`: the event did not invite `respondingAs`, or any address the key or app may send as.
- `409`: `event_cancelled`: the meeting was called off. `reply_not_sent`: the answer could not be sent to the organiser, so nothing changed.
- The errors every operation can return: `400`, `401`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.respondToEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#respondToEvent); Python [`calendar.respond_to_event()`](https://nextmail.sh/docs/python/reference/calendar#respondToEvent); Ruby [`calendar.respond_to_event`](https://nextmail.sh/docs/ruby/reference/calendar#respondToEvent); PHP [`calendar->respondToEvent`](https://nextmail.sh/docs/php/reference/calendar#respondToEvent); Go [`Calendar.RespondToEvent`](https://nextmail.sh/docs/go/reference/calendar#respondToEvent); Java [`calendar().respondToEvent`](https://nextmail.sh/docs/java/reference/calendar#respondToEvent); C# [`Calendar.RespondToEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#respondToEvent); CLI [`nextmail calendar respond-to-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-respond-to-event); MCP [`respondToCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#respondToCalendarEvent).

### `POST /calendar/events/{id}/decline-proposal`

Decline a proposed time

Keeps the original time of a meeting you organise after a guest proposed another one, as Decline in the proposal on the event does in the app. The guest is told by email from `from`, or from the organising address. To take the proposed time instead, change the event with `PATCH /calendar/events/{id}`.

Requires the `calendar:write` and `emails:send` scopes.

- Scopes: `calendar:write`, `emails:send`.

**Path parameters**

- `id` (`string`, required): The event id from `GET /calendar/events`.

**Request body**

- `attendee` (`string`, required, up to 320 characters, format `email`): The guest whose proposal you decline, by email address.
- `from` (`string`, up to 320 characters): The address the answer is sent from, when it is not the organising address.

**Returns**

- `200` `CalendarEvent`: The event, with the proposal cleared.

**Errors**

- `403`: `not_organizer`: the event was organised by somebody else. `event_read_only`: the event comes from a calendar you subscribe to.
- `404`: `proposal_not_found`: that guest has not proposed a new time. `event_not_found`: no such event.
- The errors every operation can return: `400`, `401`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.declineProposal()`](https://nextmail.sh/docs/sdk/reference/calendar#declineProposal); Python [`calendar.decline_proposal()`](https://nextmail.sh/docs/python/reference/calendar#declineProposal); Ruby [`calendar.decline_proposal`](https://nextmail.sh/docs/ruby/reference/calendar#declineProposal); PHP [`calendar->declineProposal`](https://nextmail.sh/docs/php/reference/calendar#declineProposal); Go [`Calendar.DeclineProposal`](https://nextmail.sh/docs/go/reference/calendar#declineProposal); Java [`calendar().declineProposal`](https://nextmail.sh/docs/java/reference/calendar#declineProposal); C# [`Calendar.DeclineProposalAsync`](https://nextmail.sh/docs/csharp/reference/calendar#declineProposal); CLI [`nextmail calendar decline-proposal`](https://nextmail.sh/docs/cli/reference/calendar#calendar-decline-proposal); MCP [`declineCalendarProposal`](https://nextmail.sh/docs/mcp/tools/calendar#declineCalendarProposal).

### `POST /calendar/events/{id}/hide`

Hide an event from your calendar

Takes an event off your own calendar and leaves it where it is for everyone else, as Hide from my calendar does in the app. Use it for an invitation that reached you through a shared address, or one you may not remove. It stops its reminders for you too. `POST /calendar/events/{id}/unhide` brings it back.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The event id from `GET /calendar/events`.

**Returns**

- `200` `CalendarEventHidden`: The event, hidden for you.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.hideEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#hideEvent); Python [`calendar.hide_event()`](https://nextmail.sh/docs/python/reference/calendar#hideEvent); Ruby [`calendar.hide_event`](https://nextmail.sh/docs/ruby/reference/calendar#hideEvent); PHP [`calendar->hideEvent`](https://nextmail.sh/docs/php/reference/calendar#hideEvent); Go [`Calendar.HideEvent`](https://nextmail.sh/docs/go/reference/calendar#hideEvent); Java [`calendar().hideEvent`](https://nextmail.sh/docs/java/reference/calendar#hideEvent); C# [`Calendar.HideEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#hideEvent); CLI [`nextmail calendar hide-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-hide-event); MCP [`hideCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#hideCalendarEvent).

### `POST /calendar/events/{id}/unhide`

Show a hidden event again

Puts an event you hid back on your calendar, as Show on my calendar does on the invitation in the app.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The event id from `GET /calendar/events`.

**Returns**

- `200` `CalendarEventHidden`: The event, on your calendar again.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.unhideEvent()`](https://nextmail.sh/docs/sdk/reference/calendar#unhideEvent); Python [`calendar.unhide_event()`](https://nextmail.sh/docs/python/reference/calendar#unhideEvent); Ruby [`calendar.unhide_event`](https://nextmail.sh/docs/ruby/reference/calendar#unhideEvent); PHP [`calendar->unhideEvent`](https://nextmail.sh/docs/php/reference/calendar#unhideEvent); Go [`Calendar.UnhideEvent`](https://nextmail.sh/docs/go/reference/calendar#unhideEvent); Java [`calendar().unhideEvent`](https://nextmail.sh/docs/java/reference/calendar#unhideEvent); C# [`Calendar.UnhideEventAsync`](https://nextmail.sh/docs/csharp/reference/calendar#unhideEvent); CLI [`nextmail calendar unhide-event`](https://nextmail.sh/docs/cli/reference/calendar#calendar-unhide-event); MCP [`hideCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#hideCalendarEvent).

### `GET /calendar/free-busy`

Free and busy times

When the people you name are busy, as Find a time in the event editor of the app shows it. Each address of the workspace shows the busy times of the person who holds it, from their events, the invitations they have not declined, their subscribed calendars and their bookings, without any detail. Add `durationMinutes` to get `suggestions`: the first times everyone known is free. A key or app limited to some addresses is refused, since the answer reads whole calendars.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Query parameters**

- `from` (`string`, required, format `date-time`): The start of the window.
- `to` (`string`, required, format `date-time`): A free and busy window may span at most 31 days.
- `emails` (`string`, required): The addresses to look up, at most 20. An address of the workspace shows when the person who holds it is busy; any other address comes back with `known` false. Separate them with commas.
- `timezone` (`string`, default `"UTC"`): IANA zone the suggested times keep to working hours in.
- `durationMinutes` (`integer`, at least 5, at most 480): The length of the meeting in minutes. With it, `suggestions` lists the first times everyone known is free, on weekdays between 09:00 and 17:00 in `timezone`.

**Returns**

- `200` `CalendarFreeBusy`: When each person is busy, and the suggested times.

**Errors**

- `422`: `capability_unsupported`: the key or app is limited to some addresses. `invalid_parameter`: the window, an address or the duration is not valid.
- The errors every operation can return: `400`, `401`, `403`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.freeBusy()`](https://nextmail.sh/docs/sdk/reference/calendar#freeBusy); Python [`calendar.free_busy()`](https://nextmail.sh/docs/python/reference/calendar#freeBusy); Ruby [`calendar.free_busy`](https://nextmail.sh/docs/ruby/reference/calendar#freeBusy); PHP [`calendar->freeBusy`](https://nextmail.sh/docs/php/reference/calendar#freeBusy); Go [`Calendar.FreeBusy`](https://nextmail.sh/docs/go/reference/calendar#freeBusy); Java [`calendar().freeBusy`](https://nextmail.sh/docs/java/reference/calendar#freeBusy); C# [`Calendar.FreeBusyAsync`](https://nextmail.sh/docs/csharp/reference/calendar#freeBusy); CLI [`nextmail calendar free-busy`](https://nextmail.sh/docs/cli/reference/calendar#calendar-free-busy); MCP [`findMeetingTime`](https://nextmail.sh/docs/mcp/tools/calendar#findMeetingTime).

### `GET /calendar/feeds`

List calendar links

The secret links that publish your calendar to other calendar apps, as Share in the calendar settings of the app lists them. Anyone with a link can read what it shows, so treat `url` and `webcalUrl` like passwords.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Returns**

- `200` `CalendarFeedList`: Your calendar links.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.listFeeds()`](https://nextmail.sh/docs/sdk/reference/calendar#listFeeds); Python [`calendar.list_feeds()`](https://nextmail.sh/docs/python/reference/calendar#listFeeds); Ruby [`calendar.list_feeds`](https://nextmail.sh/docs/ruby/reference/calendar#listFeeds); PHP [`calendar->listFeeds`](https://nextmail.sh/docs/php/reference/calendar#listFeeds); Go [`Calendar.ListFeeds`](https://nextmail.sh/docs/go/reference/calendar#listFeeds); Java [`calendar().listFeeds`](https://nextmail.sh/docs/java/reference/calendar#listFeeds); C# [`Calendar.ListFeedsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#listFeeds); CLI [`nextmail calendar list-feeds`](https://nextmail.sh/docs/cli/reference/calendar#calendar-list-feeds); MCP [`listCalendarFeeds`](https://nextmail.sh/docs/mcp/tools/calendar#listCalendarFeeds).

### `POST /calendar/feeds`

Create a calendar link

Makes a secret link that publishes your calendar as an iCalendar feed, for Google Calendar (From URL), Outlook (Subscribe from web) or Apple Calendar (New subscription). `full` shows every detail, `busy` only the times you are busy. The calendar app checks the link again on its own schedule, usually every few hours.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Request body**

- `name` (`string`, required, 1 to 100 characters): The name calendar apps show for the calendar, up to 100 characters.
- `mode` (`string`, required, one of `"full"`, `"busy"`): `full` for every detail, `busy` for busy times only.

**Returns**

- `201` `CalendarFeed`: The new link.

**Errors**

- `409`: `calendar_feed_limit`: you already keep the most links one person may.
- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.createFeed()`](https://nextmail.sh/docs/sdk/reference/calendar#createFeed); Python [`calendar.create_feed()`](https://nextmail.sh/docs/python/reference/calendar#createFeed); Ruby [`calendar.create_feed`](https://nextmail.sh/docs/ruby/reference/calendar#createFeed); PHP [`calendar->createFeed`](https://nextmail.sh/docs/php/reference/calendar#createFeed); Go [`Calendar.CreateFeed`](https://nextmail.sh/docs/go/reference/calendar#createFeed); Java [`calendar().createFeed`](https://nextmail.sh/docs/java/reference/calendar#createFeed); C# [`Calendar.CreateFeedAsync`](https://nextmail.sh/docs/csharp/reference/calendar#createFeed); CLI [`nextmail calendar create-feed`](https://nextmail.sh/docs/cli/reference/calendar#calendar-create-feed); MCP [`createCalendarFeed`](https://nextmail.sh/docs/mcp/tools/calendar#createCalendarFeed).

### `DELETE /calendar/feeds/{id}`

Delete a calendar link

Turns a calendar link off for good. Calendar apps that subscribed to it stop getting updates.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The calendar link id.

**Returns**

- `200` `DeletedCalendarFeed`: The link is gone.

**Errors**

- `404`: `calendar_feed_not_found`: no link of yours has that id.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.deleteFeed()`](https://nextmail.sh/docs/sdk/reference/calendar#deleteFeed); Python [`calendar.delete_feed()`](https://nextmail.sh/docs/python/reference/calendar#deleteFeed); Ruby [`calendar.delete_feed`](https://nextmail.sh/docs/ruby/reference/calendar#deleteFeed); PHP [`calendar->deleteFeed`](https://nextmail.sh/docs/php/reference/calendar#deleteFeed); Go [`Calendar.DeleteFeed`](https://nextmail.sh/docs/go/reference/calendar#deleteFeed); Java [`calendar().deleteFeed`](https://nextmail.sh/docs/java/reference/calendar#deleteFeed); C# [`Calendar.DeleteFeedAsync`](https://nextmail.sh/docs/csharp/reference/calendar#deleteFeed); CLI [`nextmail calendar delete-feed`](https://nextmail.sh/docs/cli/reference/calendar#calendar-delete-feed); MCP [`deleteCalendarFeed`](https://nextmail.sh/docs/mcp/tools/calendar#deleteCalendarFeed).

### `POST /calendar/feeds/{id}/reset`

Reset a calendar link

Replaces the secret in a calendar link, so the old address stops working everywhere it was shared. Paste the new address into the calendar apps you still want to update.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The calendar link id.

**Returns**

- `200` `CalendarFeed`: The link with its new address.

**Errors**

- `404`: `calendar_feed_not_found`: no link of yours has that id.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.resetFeed()`](https://nextmail.sh/docs/sdk/reference/calendar#resetFeed); Python [`calendar.reset_feed()`](https://nextmail.sh/docs/python/reference/calendar#resetFeed); Ruby [`calendar.reset_feed`](https://nextmail.sh/docs/ruby/reference/calendar#resetFeed); PHP [`calendar->resetFeed`](https://nextmail.sh/docs/php/reference/calendar#resetFeed); Go [`Calendar.ResetFeed`](https://nextmail.sh/docs/go/reference/calendar#resetFeed); Java [`calendar().resetFeed`](https://nextmail.sh/docs/java/reference/calendar#resetFeed); C# [`Calendar.ResetFeedAsync`](https://nextmail.sh/docs/csharp/reference/calendar#resetFeed); CLI [`nextmail calendar reset-feed`](https://nextmail.sh/docs/cli/reference/calendar#calendar-reset-feed); MCP [`resetCalendarFeed`](https://nextmail.sh/docs/mcp/tools/calendar#resetCalendarFeed).

### `GET /calendar/subscriptions`

List calendar subscriptions

The other calendars you subscribe to by link, such as a Google or Outlook calendar address, a team rota or public holidays, as Other calendars in the app lists them. Their events show on your calendar, read-only.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Returns**

- `200` `CalendarSubscriptionList`: Your subscriptions.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.listSubscriptions()`](https://nextmail.sh/docs/sdk/reference/calendar#listSubscriptions); Python [`calendar.list_subscriptions()`](https://nextmail.sh/docs/python/reference/calendar#listSubscriptions); Ruby [`calendar.list_subscriptions`](https://nextmail.sh/docs/ruby/reference/calendar#listSubscriptions); PHP [`calendar->listSubscriptions`](https://nextmail.sh/docs/php/reference/calendar#listSubscriptions); Go [`Calendar.ListSubscriptions`](https://nextmail.sh/docs/go/reference/calendar#listSubscriptions); Java [`calendar().listSubscriptions`](https://nextmail.sh/docs/java/reference/calendar#listSubscriptions); C# [`Calendar.ListSubscriptionsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#listSubscriptions); CLI [`nextmail calendar list-subscriptions`](https://nextmail.sh/docs/cli/reference/calendar#calendar-list-subscriptions); MCP [`listCalendarSubscriptions`](https://nextmail.sh/docs/mcp/tools/calendar#listCalendarSubscriptions).

### `POST /calendar/subscriptions`

Subscribe to a calendar

Adds a calendar by its iCalendar link: an `https`, `http` or `webcal` address, such as the secret address of a Google calendar or a published Outlook calendar. It is read at once, then again about every half hour. `name` defaults to the name the calendar gives itself.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Request body**

- `url` (`string`, required, 1 to 2048 characters): The calendar link, `https`, `http` or `webcal`.
- `name` (`string`, 1 to 100 characters): The name to show, up to 100 characters.
- `color` (`string`, one of `"blue"`, `"sky"`, `"teal"`, `"green"`, `"lime"`, `"yellow"`, `"orange"`, `"red"`, `"pink"`, `"purple"`, `"gray"`): The colour of its events, from `CALENDAR_COLORS`.

**Returns**

- `201` `CalendarSubscription`: The subscription, with its first events read.

**Errors**

- `409`: `calendar_subscription_exists`: you already subscribe to that address. `calendar_subscription_limit`: you already subscribe to the most calendars one person may.
- `422`: `calendar_subscription_url_invalid`: not a public https, http or webcal link. `calendar_subscription_unreadable`: nothing at the address read as a calendar.
- The errors every operation can return: `400`, `401`, `403`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.createSubscription()`](https://nextmail.sh/docs/sdk/reference/calendar#createSubscription); Python [`calendar.create_subscription()`](https://nextmail.sh/docs/python/reference/calendar#createSubscription); Ruby [`calendar.create_subscription`](https://nextmail.sh/docs/ruby/reference/calendar#createSubscription); PHP [`calendar->createSubscription`](https://nextmail.sh/docs/php/reference/calendar#createSubscription); Go [`Calendar.CreateSubscription`](https://nextmail.sh/docs/go/reference/calendar#createSubscription); Java [`calendar().createSubscription`](https://nextmail.sh/docs/java/reference/calendar#createSubscription); C# [`Calendar.CreateSubscriptionAsync`](https://nextmail.sh/docs/csharp/reference/calendar#createSubscription); CLI [`nextmail calendar create-subscription`](https://nextmail.sh/docs/cli/reference/calendar#calendar-create-subscription); MCP [`subscribeToCalendar`](https://nextmail.sh/docs/mcp/tools/calendar#subscribeToCalendar).

### `PATCH /calendar/subscriptions/{id}`

Change a calendar subscription

Renames a subscription or gives it another colour.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The subscription id.

**Request body**

- `name` (`string`, 1 to 100 characters): The new name, up to 100 characters.
- `color` (`string`, one of `"blue"`, `"sky"`, `"teal"`, `"green"`, `"lime"`, `"yellow"`, `"orange"`, `"red"`, `"pink"`, `"purple"`, `"gray"`): The new colour, from `CALENDAR_COLORS`.

**Returns**

- `200` `CalendarSubscription`: The subscription as it stands now.

**Errors**

- `404`: `calendar_subscription_not_found`: no subscription of yours has that id.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.updateSubscription()`](https://nextmail.sh/docs/sdk/reference/calendar#updateSubscription); Python [`calendar.update_subscription()`](https://nextmail.sh/docs/python/reference/calendar#updateSubscription); Ruby [`calendar.update_subscription`](https://nextmail.sh/docs/ruby/reference/calendar#updateSubscription); PHP [`calendar->updateSubscription`](https://nextmail.sh/docs/php/reference/calendar#updateSubscription); Go [`Calendar.UpdateSubscription`](https://nextmail.sh/docs/go/reference/calendar#updateSubscription); Java [`calendar().updateSubscription`](https://nextmail.sh/docs/java/reference/calendar#updateSubscription); C# [`Calendar.UpdateSubscriptionAsync`](https://nextmail.sh/docs/csharp/reference/calendar#updateSubscription); CLI [`nextmail calendar update-subscription`](https://nextmail.sh/docs/cli/reference/calendar#calendar-update-subscription); MCP [`updateCalendarSubscription`](https://nextmail.sh/docs/mcp/tools/calendar#updateCalendarSubscription).

### `DELETE /calendar/subscriptions/{id}`

Unsubscribe from a calendar

Removes a subscription and every event it brought onto your calendar.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The subscription id.

**Returns**

- `200` `DeletedCalendarSubscription`: The subscription is gone.

**Errors**

- `404`: `calendar_subscription_not_found`: no subscription of yours has that id.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.deleteSubscription()`](https://nextmail.sh/docs/sdk/reference/calendar#deleteSubscription); Python [`calendar.delete_subscription()`](https://nextmail.sh/docs/python/reference/calendar#deleteSubscription); Ruby [`calendar.delete_subscription`](https://nextmail.sh/docs/ruby/reference/calendar#deleteSubscription); PHP [`calendar->deleteSubscription`](https://nextmail.sh/docs/php/reference/calendar#deleteSubscription); Go [`Calendar.DeleteSubscription`](https://nextmail.sh/docs/go/reference/calendar#deleteSubscription); Java [`calendar().deleteSubscription`](https://nextmail.sh/docs/java/reference/calendar#deleteSubscription); C# [`Calendar.DeleteSubscriptionAsync`](https://nextmail.sh/docs/csharp/reference/calendar#deleteSubscription); CLI [`nextmail calendar delete-subscription`](https://nextmail.sh/docs/cli/reference/calendar#calendar-delete-subscription); MCP [`unsubscribeFromCalendar`](https://nextmail.sh/docs/mcp/tools/calendar#unsubscribeFromCalendar).

### `POST /calendar/subscriptions/{id}/refresh`

Refresh a calendar subscription

Reads a subscribed calendar again now instead of waiting for the next half-hourly read, and restarts one that stopped after repeated failures.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The subscription id.

**Returns**

- `200` `CalendarSubscription`: The subscription after the read.

**Errors**

- `404`: `calendar_subscription_not_found`: no subscription of yours has that id.
- `429`: `calendar_subscription_refresh_too_soon`: it was read moments ago. `rate_limited`: the key or app made more than 600 requests in 60 seconds. Wait for the seconds in `Retry-After`.
- The errors every operation can return: `400`, `401`, `403`, `422`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.refreshSubscription()`](https://nextmail.sh/docs/sdk/reference/calendar#refreshSubscription); Python [`calendar.refresh_subscription()`](https://nextmail.sh/docs/python/reference/calendar#refreshSubscription); Ruby [`calendar.refresh_subscription`](https://nextmail.sh/docs/ruby/reference/calendar#refreshSubscription); PHP [`calendar->refreshSubscription`](https://nextmail.sh/docs/php/reference/calendar#refreshSubscription); Go [`Calendar.RefreshSubscription`](https://nextmail.sh/docs/go/reference/calendar#refreshSubscription); Java [`calendar().refreshSubscription`](https://nextmail.sh/docs/java/reference/calendar#refreshSubscription); C# [`Calendar.RefreshSubscriptionAsync`](https://nextmail.sh/docs/csharp/reference/calendar#refreshSubscription); CLI [`nextmail calendar refresh-subscription`](https://nextmail.sh/docs/cli/reference/calendar#calendar-refresh-subscription); MCP [`refreshCalendarSubscription`](https://nextmail.sh/docs/mcp/tools/calendar#refreshCalendarSubscription).

### `GET /threads/{id}/event`

The event a thread carries

The calendar event that came with an invitation in the thread, as the invitation card of the reading pane shows it. A thread with no event, or one the key or app does not reach, is a 404. Answer it with `POST /calendar/events/{id}/respond`.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Path parameters**

- `id` (`string`, required): The thread id.

**Returns**

- `200` `CalendarEvent`: The event.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.threads.getEvent()`](https://nextmail.sh/docs/sdk/reference/threads#getEvent); Python [`threads.get_event()`](https://nextmail.sh/docs/python/reference/threads#getEvent); Ruby [`threads.get_event`](https://nextmail.sh/docs/ruby/reference/threads#getEvent); PHP [`threads->getEvent`](https://nextmail.sh/docs/php/reference/threads#getEvent); Go [`Threads.GetEvent`](https://nextmail.sh/docs/go/reference/threads#getEvent); Java [`threads().getEvent`](https://nextmail.sh/docs/java/reference/threads#getEvent); C# [`Threads.GetEventAsync`](https://nextmail.sh/docs/csharp/reference/threads#getEvent); CLI [`nextmail threads get-event`](https://nextmail.sh/docs/cli/reference/threads#threads-get-event); MCP [`getCalendarEvent`](https://nextmail.sh/docs/mcp/tools/calendar#getCalendarEvent).

### `GET /calendar/imports`

List calendar imports

The calendar files and calendars brought in, newest first, each with what it added and what it left out. Paging is keyset: pass `nextCursor` back as `cursor` while `hasMore` is true.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Query parameters**

- `limit` (`integer`, at least 1, at most 100, default `25`): Rows per page, 1 to 100.
- `cursor` (`string`): The previous page's `nextCursor`, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400 `invalid_cursor`.

**Returns**

- `200` `CalendarImportList`: One page of calendar imports.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.listImports()`](https://nextmail.sh/docs/sdk/reference/calendar#listImports), [`nextmail.calendar.listAllImports()`](https://nextmail.sh/docs/sdk/reference/calendar#listAllImports), [`nextmail.calendar.iterateImports()`](https://nextmail.sh/docs/sdk/reference/calendar#iterateImports); Python [`calendar.list_imports()`](https://nextmail.sh/docs/python/reference/calendar#listImports), [`calendar.list_all_imports()`](https://nextmail.sh/docs/python/reference/calendar#listAllImports), [`calendar.iterate_imports()`](https://nextmail.sh/docs/python/reference/calendar#iterateImports); Ruby [`calendar.list_imports`](https://nextmail.sh/docs/ruby/reference/calendar#listImports), [`calendar.list_all_imports`](https://nextmail.sh/docs/ruby/reference/calendar#listAllImports), [`calendar.iterate_imports`](https://nextmail.sh/docs/ruby/reference/calendar#iterateImports); PHP [`calendar->listImports`](https://nextmail.sh/docs/php/reference/calendar#listImports), [`calendar->listAllImports`](https://nextmail.sh/docs/php/reference/calendar#listAllImports), [`calendar->iterateImports`](https://nextmail.sh/docs/php/reference/calendar#iterateImports); Go [`Calendar.ListImports`](https://nextmail.sh/docs/go/reference/calendar#listImports), [`Calendar.ListAllImports`](https://nextmail.sh/docs/go/reference/calendar#listAllImports), [`Calendar.IterateImports`](https://nextmail.sh/docs/go/reference/calendar#iterateImports); Java [`calendar().listImports`](https://nextmail.sh/docs/java/reference/calendar#listImports), [`calendar().listAllImports`](https://nextmail.sh/docs/java/reference/calendar#listAllImports), [`calendar().iterateImports`](https://nextmail.sh/docs/java/reference/calendar#iterateImports); C# [`Calendar.ListImportsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#listImports), [`Calendar.ListAllImportsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#listAllImports), [`Calendar.IterateImportsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#iterateImports); CLI [`nextmail calendar list-imports`](https://nextmail.sh/docs/cli/reference/calendar#calendar-list-imports); MCP [`listCalendarImports`](https://nextmail.sh/docs/mcp/tools/calendar#listCalendarImports).

### `POST /calendar/imports`

Import a calendar file

Takes an iCalendar (.ics) file as the request body and queues it. Its events become events of your own that you can edit, and nobody on them is sent anything, now or when you change them later, unless you ask for that on the change. Poll `GET /calendar/imports/{id}` until `status` is `completed`.

The file may be 10 MB and hold 25,000 events. Several calendars in one file are merged, and the report keeps their names. An event whose UID is already in the workspace is skipped and counted, never overwritten, so sending the same file twice adds nothing.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Query parameters**

- `filename` (`string`, up to 255 characters): The name to show for the file in the list of imports.

**Request body**

Content type: `text/calendar`, `application/octet-stream`.

`binary`

**Returns**

- `201` `CalendarImport`: The import, with `status` `queued`.

**Errors**

- `400`: `not_a_calendar_file`: the body is not an iCalendar file. `item_import_empty`: the body is empty. `too_many_events`: the file holds more than 25,000 events.
- `413`: `item_import_too_large`: the file is over 10 MB.
- The errors every operation can return: `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.importIcs()`](https://nextmail.sh/docs/sdk/reference/calendar#importIcs); Python [`calendar.import_ics()`](https://nextmail.sh/docs/python/reference/calendar#importIcs); Ruby [`calendar.import_ics`](https://nextmail.sh/docs/ruby/reference/calendar#importIcs); PHP [`calendar->importIcs`](https://nextmail.sh/docs/php/reference/calendar#importIcs); Go [`Calendar.ImportIcs`](https://nextmail.sh/docs/go/reference/calendar#importIcs); Java [`calendar().importIcs`](https://nextmail.sh/docs/java/reference/calendar#importIcs); C# [`Calendar.ImportIcsAsync`](https://nextmail.sh/docs/csharp/reference/calendar#importIcs); CLI [`nextmail calendar import-ics`](https://nextmail.sh/docs/cli/reference/calendar#calendar-import-ics).

### `GET /calendar/imports/{id}`

Get a calendar import

One calendar import with its counts and its report: the calendars it read, how many events it left out and why, and up to 20 of the events it left out.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Path parameters**

- `id` (`string`, required): Calendar import id, `iimp_` followed by 24 hex characters.

**Returns**

- `200` `CalendarImport`: The import.

**Errors**

- `404`: `item_import_not_found`: no such import.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.getImport()`](https://nextmail.sh/docs/sdk/reference/calendar#getImport); Python [`calendar.get_import()`](https://nextmail.sh/docs/python/reference/calendar#getImport); Ruby [`calendar.get_import`](https://nextmail.sh/docs/ruby/reference/calendar#getImport); PHP [`calendar->getImport`](https://nextmail.sh/docs/php/reference/calendar#getImport); Go [`Calendar.GetImport`](https://nextmail.sh/docs/go/reference/calendar#getImport); Java [`calendar().getImport`](https://nextmail.sh/docs/java/reference/calendar#getImport); C# [`Calendar.GetImportAsync`](https://nextmail.sh/docs/csharp/reference/calendar#getImport); CLI [`nextmail calendar get-import`](https://nextmail.sh/docs/cli/reference/calendar#calendar-get-import); MCP [`getCalendarImport`](https://nextmail.sh/docs/mcp/tools/calendar#getCalendarImport).

### `POST /calendar/imports/{id}/undo`

Remove what a calendar import added

Deletes every event the import added, changed since or not, and marks the import `undone`. Nobody is told. Events that were skipped because they were already here are not touched.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): Calendar import id, `iimp_` followed by 24 hex characters.

**Returns**

- `200` `CalendarImport`: The import, with `status` `undone`.

**Errors**

- `404`: `item_import_not_found`: no such import.
- `409`: `item_import_not_undoable`: it is still running or was already removed.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.calendar.undoImport()`](https://nextmail.sh/docs/sdk/reference/calendar#undoImport); Python [`calendar.undo_import()`](https://nextmail.sh/docs/python/reference/calendar#undoImport); Ruby [`calendar.undo_import`](https://nextmail.sh/docs/ruby/reference/calendar#undoImport); PHP [`calendar->undoImport`](https://nextmail.sh/docs/php/reference/calendar#undoImport); Go [`Calendar.UndoImport`](https://nextmail.sh/docs/go/reference/calendar#undoImport); Java [`calendar().undoImport`](https://nextmail.sh/docs/java/reference/calendar#undoImport); C# [`Calendar.UndoImportAsync`](https://nextmail.sh/docs/csharp/reference/calendar#undoImport); CLI [`nextmail calendar undo-import`](https://nextmail.sh/docs/cli/reference/calendar#calendar-undo-import); MCP [`undoCalendarImport`](https://nextmail.sh/docs/mcp/tools/calendar#undoCalendarImport).

### Objects

#### `CalendarEvent`

`object`

- `object` (`string`, required, one of `"calendar_event"`)
- `id` (`string`, required)
- `uid` (`string`, required): The iCalendar UID every copy of the event shares.
- `sequence` (`integer`, at least 0)
- `summary` (`string`, nullable)
- `description` (`string`, nullable)
- `location` (`string`, nullable)
- `url` (`string`, nullable)
- `meetingUrl` (`string`, nullable): The link to the video call, which the apps show as a Join button.
- `start` (`string`, required, format `date-time`)
- `end` (`string`, required, format `date-time`)
- `allDay` (`boolean`)
- `timezone` (`string`, nullable)
- `recurrence` (`string`, nullable): The RRULE, when it repeats.
- `exdates` (`string[]`): Occurrences left out: an instant, or a date for an all-day event.
- `rdates` (`string[]`): Extra occurrences outside the rule: an instant, or a date for an all-day event.
- `recurrenceId` (`string`, nullable, format `date-time`): For one changed occurrence of a repeating event, the start it replaces.
- `subscriptionId` (`string`, nullable): The calendar subscription it comes from, or null for your own calendar.
- `status` (`string`, required): `CONFIRMED`, `TENTATIVE` or `CANCELLED`.
- `transparency` (`string`)
- `visibility` (`string`)
- `organizer` (`object`, nullable)
  - `email` (`string`)
  - `name` (`string`, nullable)
- `isOrganizer` (`boolean`): Whether you organise it, and so may change it.
- `hidden` (`boolean`): Whether you hid it from your own calendar with `POST /calendar/events/{id}/hide`. Only `GET /calendar/events/{id}` says.
- `source` (`string`)
- `messageId` (`string`, nullable)
- `threadId` (`string`, nullable)
- `alarms` (`object[]`)
  - `minutesBefore` (`integer`)
  - `action` (`string`)
- `attendees` (`object[]`, required)
  - `object` (`string`, one of `"calendar_attendee"`)
  - `email` (`string`)
  - `name` (`string`, nullable)
  - `partstat` (`string`): `NEEDS-ACTION`, `ACCEPTED`, `DECLINED` or `TENTATIVE`.
  - `role` (`string`)
  - `rsvp` (`boolean`)
  - `cutype` (`string`, nullable)
  - `respondedAt` (`string`, nullable, format `date-time`)
  - `proposedStart` (`string`, nullable, format `date-time`): The start this guest proposed instead, until the organiser answers.
  - `proposedEnd` (`string`, nullable, format `date-time`)
- `createdAt` (`string`, format `date-time`)
- `updatedAt` (`string`, format `date-time`)

#### `CalendarEventHidden`

`object`

- `object` (`string`, required, one of `"calendar_event"`)
- `id` (`string`, required)
- `uid` (`string`, required): The iCalendar UID. Hiding reaches every date of it.
- `hidden` (`boolean`, required)

#### `CalendarFeed`

`object`

- `object` (`string`, required, one of `"calendar_feed"`)
- `id` (`string`, required)
- `name` (`string`, required): The name calendar apps show for the calendar.
- `mode` (`string`, required, one of `"full"`, `"busy"`): `full` shows every detail, `busy` only when you are busy.
- `url` (`string`, required): The https address to paste into a calendar app.
- `webcalUrl` (`string`, required): The same address as a webcal link, which opens a calendar app.
- `readCount` (`integer`, required, at least 0): Roughly how often calendar apps have read it.
- `lastReadAt` (`string`, required, nullable, format `date-time`)
- `createdAt` (`string`, required, format `date-time`)

#### `CalendarFeedList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`CalendarFeed[]`)

#### `CalendarFreeBusy`

`object`

- `object` (`string`, required, one of `"calendar_free_busy"`)
- `from` (`string`, required, format `date-time`)
- `to` (`string`, required, format `date-time`)
- `timezone` (`string`, required)
- `people` (`object[]`, required)
  - `email` (`string`, required)
  - `known` (`boolean`, required): Whether the address belongs to the workspace, so its times are known.
  - `busy` (`object[]`, required)
    - `start` (`string`, required, format `date-time`)
    - `end` (`string`, required, format `date-time`)
- `suggestions` (`object[]`, required): Times everyone known is free, when `durationMinutes` was sent.
  - `start` (`string`, required, format `date-time`)
  - `end` (`string`, required, format `date-time`)

#### `CalendarImport`

`object`

- `object` (`string`, required, one of `"calendar_import"`)
- `id` (`string`, required): `iimp_` followed by 24 hex characters.
- `kind` (`string`, required, one of `"calendar"`)
- `source` (`string`, required, one of `"file"`, `"takeout"`, `"caldav"`, `"carddav"`, `"microsoft"`): `file` is an upload. The others came with a mailbox import: `takeout` from a Google Takeout archive, `caldav` and `carddav` from the old provider, `microsoft` from an Outlook sign-in.
- `status` (`string`, required, one of `"uploading"`, `"queued"`, `"running"`, `"completed"`, `"failed"`, `"cancelled"`, `"undone"`): `undone` means what it brought in was removed again.
- `fileName` (`string`, required, nullable)
- `fileBytes` (`integer`, required, at least 0)
- `parentImportId` (`string`, required, nullable): The mailbox import it came with, when there was one.
- `counts` (`object`, required)
  - `total` (`integer`, required, at least 0): Items found so far.
  - `imported` (`integer`, required, at least 0): Items added.
  - `merged` (`integer`, required, at least 0): Contacts left as they were because the address book already holds them. Always 0 on a calendar import, where an event that is already here is counted under `skipped`.
  - `skipped` (`integer`, required, at least 0): Items left out for a reason given in `report`.
  - `failed` (`integer`, required, at least 0)
- `report` (`object`, required)
  - `collections` (`object[]`, required): The calendars or address books the items came from, by their original name.
    - `name` (`string`, required)
    - `items` (`integer`, required, at least 0)
  - `skipped` (`Record<string, integer>`, required): How many items were left out, by reason.
  - `samples` (`object[]`, required): Up to 20 of the items left out.
    - `name` (`string`, required)
    - `reason` (`string`, required, one of `"uid-taken"`, `"no-start"`, `"duplicate"`, `"limit"`, `"invalid"`, `"empty"`)
- `lastError` (`string`, required, nullable)
- `undoable` (`boolean`, required): Whether the undo call would remove anything.
- `createdAt` (`string`, required, format `date-time`)
- `startedAt` (`string`, required, nullable, format `date-time`)
- `finishedAt` (`string`, required, nullable, format `date-time`)
- `undoneAt` (`string`, required, nullable, format `date-time`)

#### `CalendarImportList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`CalendarImport[]`)
- `hasMore` (`boolean`): True when another page follows. Pass `nextCursor` back as `cursor` to read it.
- `nextCursor` (`string`, nullable): An opaque cursor for the next page, or null on the last page. Pass it back unchanged.

#### `CalendarOccurrence`

`object`

- `object` (`string`, required, one of `"calendar_occurrence"`)
- `eventId` (`string`, required)
- `uid` (`string`, required): The iCalendar UID every copy of the event shares.
- `start` (`string`, required, format `date-time`)
- `end` (`string`, required, format `date-time`)
- `allDay` (`boolean`, required)
- `summary` (`string`, required, nullable)
- `location` (`string`, required, nullable)
- `meetingUrl` (`string`, nullable): The link to the video call, when it has one.
- `status` (`string`, required): `CONFIRMED`, `TENTATIVE` or `CANCELLED`.
- `transparency` (`string`, required)
- `isOrganizer` (`boolean`, required): Whether you organise it, and so may change it.
- `organizerEmail` (`string`, required, nullable)
- `recurring` (`boolean`, required): Whether this is one occurrence of a repeating event.
- `myPartstat` (`string`, required, nullable): Your answer to the invitation, when you were invited.
- `attendeeCount` (`integer`, required, at least 0)
- `subscriptionId` (`string`, nullable): The calendar subscription it comes from, or null for your own calendar.

#### `CalendarOccurrenceList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`CalendarOccurrence[]`)
- `hasMore` (`boolean`): True when another page follows. Pass `nextCursor` back as `cursor` to read it.
- `nextCursor` (`string`, nullable): An opaque cursor for the next page, or null on the last page. Pass it back unchanged.

#### `CalendarSubscription`

`object`

- `object` (`string`, required, one of `"calendar_subscription"`)
- `id` (`string`, required)
- `name` (`string`, required)
- `url` (`string`, required): The https address it is read from.
- `color` (`string`, required, one of `"blue"`, `"sky"`, `"teal"`, `"green"`, `"lime"`, `"yellow"`, `"orange"`, `"red"`, `"pink"`, `"purple"`, `"gray"`)
- `status` (`string`, required, one of `"active"`, `"failing"`, `"stopped"`): `active`, `failing` while reads fail and are retried, or `stopped` after ten failures in a row until you refresh it.
- `lastError` (`string`, required, nullable, one of `"unreachable"`, `"too-large"`, `"not-a-calendar"`, `"too-many-events"`): Why the last read failed, if it did.
- `eventCount` (`integer`, required, at least 0)
- `lastSyncedAt` (`string`, required, nullable, format `date-time`)
- `lastFetchedAt` (`string`, required, nullable, format `date-time`)
- `createdAt` (`string`, required, format `date-time`)

#### `CalendarSubscriptionList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`CalendarSubscription[]`)

#### `DeletedCalendarEvent`

`object`

- `object` (`string`, required, one of `"calendar_event"`)
- `id` (`string`, required)
- `deleted` (`boolean`, required, one of `true`)

#### `DeletedCalendarFeed`

`object`

- `object` (`string`, required, one of `"calendar_feed"`)
- `id` (`string`, required)
- `deleted` (`boolean`, required, one of `true`)

#### `DeletedCalendarSubscription`

`object`

- `object` (`string`, required, one of `"calendar_subscription"`)
- `id` (`string`, required)
- `deleted` (`boolean`, required, one of `true`)
