---
title: "Booking pages"
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/booking-pages"
area: "API"
category: "Reference"
---

# Booking pages

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

## Operations

A booking page is a public link, `/book/<slug>`, where somebody picks a free time and books a meeting on a person's calendar. The times it offers are the working hours of the page with everything taken out that makes the person busy: their calendar events, invitations they have not declined, calendars they subscribed to, bookings they already have, the gaps the page keeps around meetings, and the days they are out of office. A booking is a calendar event with the guest invited, so it shows wherever the calendar does. A booking page belongs to one person. An API key acts as the workspace owner and reaches the pages of the owner, and a connected app reaches the pages of the person who connected it.

### `GET /booking-pages`

List booking pages

Every booking page of the person, oldest first unless `sort` says otherwise, each with its settings, its public link and how many bookings are upcoming or wait for approval. `q`, `status`, `since` and `until` narrow the list. A booking page belongs to one person. An API key acts as the workspace owner and reaches the pages of the owner, and a connected app reaches the pages of the person who connected it.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Query parameters**

- `q` (`string`, up to 200 characters): Only the pages whose name or link contains this text, at most 200 characters. Case and accents are ignored.
- `status` (`string`, one of `"active"`, `"paused"`): `active` for the pages that take bookings, `paused` for the ones that do not. Left out, both.
- `since` (`string`, format `date-time`): Only the pages made at or after this instant, as a `Date` or an ISO 8601 string.
- `until` (`string`, format `date-time`): Only the pages made before this instant, later than `since`.
- `sort` (`string`, one of `"oldest"`, `"newest"`, `"name"`, `"upcoming"`): `oldest` (the default) or `newest` by when the page was made, `name` from A to Z, or `upcoming` with the most upcoming meetings first.

**Returns**

- `200` `BookingPageList`: The booking pages.

**Errors**

- `422`: `invalid_parameter`: a query value is malformed, or `until` is not later than `since`. `capability_unsupported`: the key or app is limited to particular addresses.
- 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.bookings.listPages()`](https://nextmail.sh/docs/sdk/reference/bookings#listPages); Python [`bookings.list_pages()`](https://nextmail.sh/docs/python/reference/bookings#listPages); Ruby [`bookings.list_pages`](https://nextmail.sh/docs/ruby/reference/bookings#listPages); PHP [`bookings->listPages`](https://nextmail.sh/docs/php/reference/bookings#listPages); Go [`Bookings.ListPages`](https://nextmail.sh/docs/go/reference/bookings#listPages); Java [`bookings().listPages`](https://nextmail.sh/docs/java/reference/bookings#listPages); C# [`Bookings.ListPagesAsync`](https://nextmail.sh/docs/csharp/reference/bookings#listPages); CLI [`nextmail bookings list-pages`](https://nextmail.sh/docs/cli/reference/bookings#bookings-list-pages); MCP [`listBookingPages`](https://nextmail.sh/docs/mcp/tools/bookings#listBookingPages).

### `POST /booking-pages`

Create a booking page

Creates a booking page that takes bookings at once. Only `name` is required: the page starts with weekdays from 09:00 to 17:00, 30 minute meetings, four hours of notice and the first address the person may send from. Anything in `config` replaces that default. A person holds at most 25 pages.

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

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

**Request body**

- `name` (`string`, required, 1 to 80 characters): What the page is called, shown to guests as its heading, such as `Intro call`.
- `slug` (`string`, 1 to 60 characters): The last part of the public link, `/book/<slug>`: lowercase letters, digits and hyphens. Left out, it is made from the name. It is unique across Nextmail.
- `timezone` (`string`, 1 to 64 characters): The IANA time zone the working hours are read in, such as `Europe/Berlin`, for a new page whose `config.availability.timezone` is not sent. Defaults to `UTC`.
- `config` (`object`): The settings of the page. Send only the parts that change: a top-level value replaces the stored one, and inside `location`, `availability`, `rules`, `appearance`, `guestChanges`, `busy` and `seo` each field is merged on its own. A list (`durations`, `questions`, `availability.weekly`, `availability.overrides`) is replaced whole.
  - `description` (`string`, up to 2000 characters): Text shown under the name of the page. Basic Markdown works: bold, italic, links and lists.
  - `hostName` (`string`, up to 80 characters): The name guests see as the person they meet. Defaults to the name of the account.
  - `durations` (`integer[]`, 1 to 4 items): The meeting lengths a guest can pick, in minutes, each a multiple of 5 between 5 and 720.
  - `approval` (`boolean`): True holds each new booking as a request until it is approved or declined. False confirms it at once.
  - `fromEmail` (`string`, up to 320 characters): The address the booking emails are sent from and the calendar events are organised by. It has to be one the owner of the page may send from.
  - `notifyHost` (`boolean`): Whether that address gets an email about each new, moved or cancelled booking.
  - `questions` (`object[]`, up to 10 items): What the guest is asked besides their name and email, at most 10.
    - `id` (`string`, required, pattern `^[a-z0-9]{4,16}$`): A stable key for the answers: 4 to 16 lowercase letters and digits, unique on the page. `name`, `email`, `phone`, `timezone` and `start` are taken.
    - `kind` (`string`, required, one of `"text"`, `"long-text"`, `"phone"`, `"choice"`, `"checkbox"`): `text`, `long-text`, `phone`, `choice` (one of `options`) or `checkbox`.
    - `label` (`string`, required, 1 to 120 characters)
    - `required` (`boolean`, required)
    - `options` (`string[]`, required, up to 12 items): The answers of a `choice` question, at least two. Empty for the other kinds.
    - `placeholder` (`string`, up to 160 characters): Example text shown in the empty field of a `text`, `long-text` or `phone` question, such as `Anything we should know before the meeting?`. Up to 160 characters, empty for none. A `choice` or `checkbox` question ignores it.
  - `confirmation` (`string`, up to 1000 characters): Text shown to the guest after booking, and added to the confirmation email.
  - `redirectUrl` (`string`, up to 2000 characters): An `https://` page to send the guest to after booking, or empty.
  - `extraGuests` (`integer`, at least 0, at most 10): How many other people a guest may add to a booking, 0 to 10. Each one gets the invitation and every later change. Defaults to 0, which hides the field.
  - `reminders` (`object`): When the guest is emailed a reminder and when the host is reminded, each a list of minutes before the start.
    - `guest` (`integer[]`, up to 3 items): Minutes before the start to email the guest a reminder, at most 3, each one of 10, 30, 60, 120, 1440, 2880, 10080. Defaults to one day before. An empty list sends none.
    - `host` (`integer[]`, up to 3 items): Minutes before the start the host is reminded by the alarm on the meeting in their calendar, at most 3, each one of 0, 5, 10, 15, 30, 60, 1440. Defaults to 10. It applies to meetings booked after it changes.
  - `location` (`object`): Where the meeting happens.
    - `kind` (`string`, one of `"video"`, `"phone"`, `"in-person"`, `"none"`): `video` with a fixed link in `value`, `phone` (the guest is asked for a number), `in-person` with the address in `value`, or `none`.
    - `value` (`string`, up to 500 characters): The `https://` link of a `video` meeting or the address of an `in-person` one.
  - `availability` (`object`): When the page offers times, before the calendar is taken out.
    - `timezone` (`string`, 1 to 64 characters): The IANA time zone the hours below are read in.
    - `weekly` (`object[][]`, 7 to 7 items): Seven lists, Sunday first, of the hours open on that weekday. An empty list closes the day.
      - `start` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range opens, so `540` is 09:00.
      - `end` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range closes, later than `start`.
    - `overrides` (`object[]`, up to 180 items): Dates with their own hours, at most 180. `date` is `YYYY-MM-DD` in the time zone of the page, and an empty `ranges` closes that date.
      - `date` (`string`, required)
      - `ranges` (`object[]`, required, up to 6 items)
        - `start` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range opens, so `540` is 09:00.
        - `end` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range closes, later than `start`.
  - `rules` (`object`): The limits on which of the open hours are offered.
    - `noticeMinutes` (`integer`, at least 0, at most 43200): How many minutes ahead a booking has to be made.
    - `horizonDays` (`integer`, at least 1, at most 365): How many days ahead the page offers times, up to 365.
    - `intervalMinutes` (`integer`, nullable): Minutes between two start times, one of 5, 10, 15, 20, 30, 45, 60, 90, 120. Null steps by the length of the meeting.
    - `bufferBeforeMinutes` (`integer`, at least 0, at most 240): Minutes kept free before every meeting, up to 240.
    - `bufferAfterMinutes` (`integer`, at least 0, at most 240): Minutes kept free after every meeting, up to 240.
    - `dailyLimit` (`integer`, nullable, at least 1, at most 50): The most bookings this page takes on one day, up to 50. Null for no limit.
  - `appearance` (`object`): How the public page looks.
    - `accent` (`string`, pattern `^#[0-9a-f]{6}$`): The colour of buttons and the picked day, as `#rrggbb`.
    - `theme` (`string`, one of `"auto"`, `"light"`, `"dark"`): `auto` follows the device of the guest, or force `light` or `dark`.
    - `showAvatar` (`boolean`)
    - `background` (`string`, default `"default"`): What fills the page behind the card: `default`, one of the presets `dusk`, `mist`, `sand`, `night`, `meadow`, `dots`, `brush`, `trail`, `ember`, `canvas`, `bloom`, `field`, `wanderer` and `gold`, `image` for the uploaded background image, or a colour as `#rrggbb`. Defaults to `default`.
    - `fonts` (`object`, default `{"primary":null,"secondary":null}`): The typefaces of the public page: `primary` for its text and `secondary` for its title. Each is one of the brand fonts the workspace appearance offers, or null for the standard font.
      - `primary` (`string`, nullable, one of `"system"`, `"arial"`, `"helvetica"`, `"verdana"`, `"tahoma"`, `"trebuchet-ms"`, `"georgia"`, `"times-new-roman"`, `"courier-new"`, `"dm-sans"`, `"inter"`, `"roboto"`, `"open-sans"`, `"lato"`, `"montserrat"`, `"poppins"`, `"nunito"`, `"work-sans"`, `"source-sans-3"`, `"ibm-plex-sans"`, `"merriweather"`, `"playfair-display"`, `"instrument-serif"`, `"jetbrains-mono"`, `"dm-mono"`, `"geist-mono"`, default `null`): The font of the text, such as `inter`. Null uses the standard font.
      - `secondary` (`string`, nullable, one of `"system"`, `"arial"`, `"helvetica"`, `"verdana"`, `"tahoma"`, `"trebuchet-ms"`, `"georgia"`, `"times-new-roman"`, `"courier-new"`, `"dm-sans"`, `"inter"`, `"roboto"`, `"open-sans"`, `"lato"`, `"montserrat"`, `"poppins"`, `"nunito"`, `"work-sans"`, `"source-sans-3"`, `"ibm-plex-sans"`, `"merriweather"`, `"playfair-display"`, `"instrument-serif"`, `"jetbrains-mono"`, `"dm-mono"`, `"geist-mono"`, default `null`): The font of the title, such as `instrument-serif`. Null keeps the title in the font of the text.
    - `backgroundImage` (`string`, nullable, up to 2000 characters, default `null`): The address of the uploaded background image, or null. Read only: upload one with `PUT /booking-pages/{id}/background` and remove it with `DELETE` on the same path.
  - `guestChanges` (`object`): What a guest may do from the link in their emails.
    - `cancel` (`boolean`)
    - `reschedule` (`boolean`)
    - `cutoffMinutes` (`integer`, at least 0, at most 20160): How many minutes before the meeting those changes close.
  - `busy` (`object`): What counts as busy besides the events the person made and the bookings they already have.
    - `addresses` (`string[]`, nullable, up to 50 items): The addresses whose invitations block time unless declined. Null checks every address the person holds.
    - `subscriptions` (`boolean`): Whether events from calendars the person subscribed to block time.
    - `outOfOffice` (`boolean`, default `true`): Whether the page offers no times while `fromEmail` is out of office. Defaults to true.
  - `seo` (`object`): How the public page presents itself to browsers and search engines.
    - `title` (`string`, up to 120 characters, default `""`): The title of the browser tab and of a search result. Empty uses the name of the page and the host.
    - `description` (`string`, up to 300 characters, default `""`): The summary under the title in a search result. Empty uses the start of the description.
    - `indexable` (`boolean`, default `false`): Whether search engines may list the page. False, the default, asks them not to.

**Returns**

- `201` `BookingPage`: The page as it is stored.

**Errors**

- `403`: The key lacks a scope. `booking_page_limit_reached`: the person holds as many pages as they may.
- `409`: `booking_link_taken`: another page already uses that `slug`.
- `422`: `invalid_parameter`: a field is missing or malformed. `invalid_booking_page`: the link, the sender or a setting is not valid, as the message says. `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.createPage()`](https://nextmail.sh/docs/sdk/reference/bookings#createPage); Python [`bookings.create_page()`](https://nextmail.sh/docs/python/reference/bookings#createPage); Ruby [`bookings.create_page`](https://nextmail.sh/docs/ruby/reference/bookings#createPage); PHP [`bookings->createPage`](https://nextmail.sh/docs/php/reference/bookings#createPage); Go [`Bookings.CreatePage`](https://nextmail.sh/docs/go/reference/bookings#createPage); Java [`bookings().createPage`](https://nextmail.sh/docs/java/reference/bookings#createPage); C# [`Bookings.CreatePageAsync`](https://nextmail.sh/docs/csharp/reference/bookings#createPage); CLI [`nextmail bookings create-page`](https://nextmail.sh/docs/cli/reference/bookings#bookings-create-page); MCP [`createBookingPage`](https://nextmail.sh/docs/mcp/tools/bookings#createBookingPage).

### `GET /booking-pages/{id}`

Read a booking page

One booking page with every setting, what stops it from taking bookings if anything does, and the out of office periods that close it.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Path parameters**

- `id` (`string`, required): The booking page, such as `bkp_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /booking-pages` lists it.

**Returns**

- `200` `BookingPage`: The page.

**Errors**

- `404`: `booking_page_not_found`: the person has no booking page with that id.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.getPage()`](https://nextmail.sh/docs/sdk/reference/bookings#getPage); Python [`bookings.get_page()`](https://nextmail.sh/docs/python/reference/bookings#getPage); Ruby [`bookings.get_page`](https://nextmail.sh/docs/ruby/reference/bookings#getPage); PHP [`bookings->getPage`](https://nextmail.sh/docs/php/reference/bookings#getPage); Go [`Bookings.GetPage`](https://nextmail.sh/docs/go/reference/bookings#getPage); Java [`bookings().getPage`](https://nextmail.sh/docs/java/reference/bookings#getPage); C# [`Bookings.GetPageAsync`](https://nextmail.sh/docs/csharp/reference/bookings#getPage); CLI [`nextmail bookings get-page`](https://nextmail.sh/docs/cli/reference/bookings#bookings-get-page); MCP [`getBookingPage`](https://nextmail.sh/docs/mcp/tools/bookings#getBookingPage).

### `PATCH /booking-pages/{id}`

Update a booking page

Changes the name, the link, the status or any setting of a page. Send only what changes. Set `status` to `paused` to stop offering times without losing the link. Bookings already made keep their time, and a new `slug` stops the old link from working.

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

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

**Path parameters**

- `id` (`string`, required): The booking page, such as `bkp_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /booking-pages` lists it.

**Request body**

- `name` (`string`, 1 to 80 characters): What the page is called, shown to guests as its heading, such as `Intro call`.
- `slug` (`string`, 1 to 60 characters): The last part of the public link, `/book/<slug>`: lowercase letters, digits and hyphens. It is unique across Nextmail. Left out, the stored link stays.
- `status` (`string`, one of `"active"`, `"paused"`): `active` takes bookings. `paused` keeps the link working but offers no times.
- `config` (`object`): The settings of the page. Send only the parts that change: a top-level value replaces the stored one, and inside `location`, `availability`, `rules`, `appearance`, `guestChanges`, `busy` and `seo` each field is merged on its own. A list (`durations`, `questions`, `availability.weekly`, `availability.overrides`) is replaced whole.
  - `description` (`string`, up to 2000 characters): Text shown under the name of the page. Basic Markdown works: bold, italic, links and lists.
  - `hostName` (`string`, up to 80 characters): The name guests see as the person they meet. Left out, the stored name stays.
  - `durations` (`integer[]`, 1 to 4 items): The meeting lengths a guest can pick, in minutes, each a multiple of 5 between 5 and 720.
  - `approval` (`boolean`): True holds each new booking as a request until it is approved or declined. False confirms it at once.
  - `fromEmail` (`string`, up to 320 characters): The address the booking emails are sent from and the calendar events are organised by. It has to be one the owner of the page may send from.
  - `notifyHost` (`boolean`): Whether that address gets an email about each new, moved or cancelled booking.
  - `questions` (`object[]`, up to 10 items): What the guest is asked besides their name and email, at most 10.
    - `id` (`string`, required, pattern `^[a-z0-9]{4,16}$`): A stable key for the answers: 4 to 16 lowercase letters and digits, unique on the page. `name`, `email`, `phone`, `timezone` and `start` are taken.
    - `kind` (`string`, required, one of `"text"`, `"long-text"`, `"phone"`, `"choice"`, `"checkbox"`): `text`, `long-text`, `phone`, `choice` (one of `options`) or `checkbox`.
    - `label` (`string`, required, 1 to 120 characters)
    - `required` (`boolean`, required)
    - `options` (`string[]`, required, up to 12 items): The answers of a `choice` question, at least two. Empty for the other kinds.
    - `placeholder` (`string`, up to 160 characters): Example text shown in the empty field of a `text`, `long-text` or `phone` question, such as `Anything we should know before the meeting?`. Up to 160 characters, empty for none. A `choice` or `checkbox` question ignores it.
  - `confirmation` (`string`, up to 1000 characters): Text shown to the guest after booking, and added to the confirmation email.
  - `redirectUrl` (`string`, up to 2000 characters): An `https://` page to send the guest to after booking, or empty.
  - `extraGuests` (`integer`, at least 0, at most 10): How many other people a guest may add to a booking, 0 to 10. Each one gets the invitation and every later change, and 0 hides the field. Left out, the stored number stays.
  - `reminders` (`object`): When the guest is emailed a reminder and when the host is reminded, each a list of minutes before the start.
    - `guest` (`integer[]`, up to 3 items): Minutes before the start to email the guest a reminder, at most 3, each one of 10, 30, 60, 120, 1440, 2880, 10080. An empty list sends none. Left out, the stored list stays.
    - `host` (`integer[]`, up to 3 items): Minutes before the start the host is reminded by the alarm on the meeting in their calendar, at most 3, each one of 0, 5, 10, 15, 30, 60, 1440. It applies to meetings booked after it changes. Left out, the stored list stays.
  - `location` (`object`): Where the meeting happens.
    - `kind` (`string`, one of `"video"`, `"phone"`, `"in-person"`, `"none"`): `video` with a fixed link in `value`, `phone` (the guest is asked for a number), `in-person` with the address in `value`, or `none`.
    - `value` (`string`, up to 500 characters): The `https://` link of a `video` meeting or the address of an `in-person` one.
  - `availability` (`object`): When the page offers times, before the calendar is taken out.
    - `timezone` (`string`, 1 to 64 characters): The IANA time zone the hours below are read in.
    - `weekly` (`object[][]`, 7 to 7 items): Seven lists, Sunday first, of the hours open on that weekday. An empty list closes the day.
      - `start` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range opens, so `540` is 09:00.
      - `end` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range closes, later than `start`.
    - `overrides` (`object[]`, up to 180 items): Dates with their own hours, at most 180. `date` is `YYYY-MM-DD` in the time zone of the page, and an empty `ranges` closes that date.
      - `date` (`string`, required)
      - `ranges` (`object[]`, required, up to 6 items)
        - `start` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range opens, so `540` is 09:00.
        - `end` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range closes, later than `start`.
  - `rules` (`object`): The limits on which of the open hours are offered.
    - `noticeMinutes` (`integer`, at least 0, at most 43200): How many minutes ahead a booking has to be made.
    - `horizonDays` (`integer`, at least 1, at most 365): How many days ahead the page offers times, up to 365.
    - `intervalMinutes` (`integer`, nullable): Minutes between two start times, one of 5, 10, 15, 20, 30, 45, 60, 90, 120. Null steps by the length of the meeting.
    - `bufferBeforeMinutes` (`integer`, at least 0, at most 240): Minutes kept free before every meeting, up to 240.
    - `bufferAfterMinutes` (`integer`, at least 0, at most 240): Minutes kept free after every meeting, up to 240.
    - `dailyLimit` (`integer`, nullable, at least 1, at most 50): The most bookings this page takes on one day, up to 50. Null for no limit.
  - `appearance` (`object`): How the public page looks.
    - `accent` (`string`, pattern `^#[0-9a-f]{6}$`): The colour of buttons and the picked day, as `#rrggbb`.
    - `theme` (`string`, one of `"auto"`, `"light"`, `"dark"`): `auto` follows the device of the guest, or force `light` or `dark`.
    - `showAvatar` (`boolean`)
    - `background` (`string`): What fills the page behind the card: `default`, one of the presets `dusk`, `mist`, `sand`, `night`, `meadow`, `dots`, `brush`, `trail`, `ember`, `canvas`, `bloom`, `field`, `wanderer` and `gold`, `image` for the uploaded background image, or a colour as `#rrggbb`. Left out, the stored background stays.
    - `fonts` (`object`): The typefaces of the public page, merged by key: `primary` for its text and `secondary` for its title, each a brand font or null for the standard font. Left out, the stored fonts stay.
      - `primary` (`string`, nullable, one of `"system"`, `"arial"`, `"helvetica"`, `"verdana"`, `"tahoma"`, `"trebuchet-ms"`, `"georgia"`, `"times-new-roman"`, `"courier-new"`, `"dm-sans"`, `"inter"`, `"roboto"`, `"open-sans"`, `"lato"`, `"montserrat"`, `"poppins"`, `"nunito"`, `"work-sans"`, `"source-sans-3"`, `"ibm-plex-sans"`, `"merriweather"`, `"playfair-display"`, `"instrument-serif"`, `"jetbrains-mono"`, `"dm-mono"`, `"geist-mono"`): The font of the text, such as `inter`. Null uses the standard font.
      - `secondary` (`string`, nullable, one of `"system"`, `"arial"`, `"helvetica"`, `"verdana"`, `"tahoma"`, `"trebuchet-ms"`, `"georgia"`, `"times-new-roman"`, `"courier-new"`, `"dm-sans"`, `"inter"`, `"roboto"`, `"open-sans"`, `"lato"`, `"montserrat"`, `"poppins"`, `"nunito"`, `"work-sans"`, `"source-sans-3"`, `"ibm-plex-sans"`, `"merriweather"`, `"playfair-display"`, `"instrument-serif"`, `"jetbrains-mono"`, `"dm-mono"`, `"geist-mono"`): The font of the title, such as `instrument-serif`. Null keeps the title in the font of the text.
    - `backgroundImage` (`string`, nullable, up to 2000 characters): Read only. Sending it back as you read it changes nothing; upload or remove the image on the background path of the page.
  - `guestChanges` (`object`): What a guest may do from the link in their emails.
    - `cancel` (`boolean`)
    - `reschedule` (`boolean`)
    - `cutoffMinutes` (`integer`, at least 0, at most 20160): How many minutes before the meeting those changes close.
  - `busy` (`object`): What counts as busy besides the events the person made and the bookings they already have.
    - `addresses` (`string[]`, nullable, up to 50 items): The addresses whose invitations block time unless declined. Null checks every address the person holds.
    - `subscriptions` (`boolean`): Whether events from calendars the person subscribed to block time.
    - `outOfOffice` (`boolean`): Whether the page offers no times while `fromEmail` is out of office. Left out, the stored setting stays.
  - `seo` (`object`): How the public page presents itself to browsers and search engines.
    - `title` (`string`, up to 120 characters): The title of the browser tab and of a search result. Empty uses the name of the page and the host.
    - `description` (`string`, up to 300 characters): The summary under the title in a search result. Empty uses the start of the description.
    - `indexable` (`boolean`): Whether search engines may list the page. False asks them not to. Left out, the stored setting stays.

**Returns**

- `200` `BookingPage`: The page after the change.

**Errors**

- `404`: `booking_page_not_found`: the person has no booking page with that id.
- `409`: `booking_link_taken`: another page already uses that `slug`.
- `422`: `invalid_parameter`: nothing to change was sent or a field is malformed. `invalid_booking_page`: the link, the sender or a setting is not valid, as the message says. `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.updatePage()`](https://nextmail.sh/docs/sdk/reference/bookings#updatePage); Python [`bookings.update_page()`](https://nextmail.sh/docs/python/reference/bookings#updatePage); Ruby [`bookings.update_page`](https://nextmail.sh/docs/ruby/reference/bookings#updatePage); PHP [`bookings->updatePage`](https://nextmail.sh/docs/php/reference/bookings#updatePage); Go [`Bookings.UpdatePage`](https://nextmail.sh/docs/go/reference/bookings#updatePage); Java [`bookings().updatePage`](https://nextmail.sh/docs/java/reference/bookings#updatePage); C# [`Bookings.UpdatePageAsync`](https://nextmail.sh/docs/csharp/reference/bookings#updatePage); CLI [`nextmail bookings update-page`](https://nextmail.sh/docs/cli/reference/bookings#bookings-update-page); MCP [`updateBookingPage`](https://nextmail.sh/docs/mcp/tools/bookings#updateBookingPage).

### `DELETE /booking-pages/{id}`

Delete a booking page

Deletes a booking page for good. Its link stops working and the list of its bookings goes with it, so guests can no longer move or cancel through their links. The meetings already booked stay on the calendar.

Requires the `calendar:write` scope.

- Scopes: `calendar:write`.

**Path parameters**

- `id` (`string`, required): The booking page, such as `bkp_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /booking-pages` lists it.

**Returns**

- `200` `DeletedBookingPage`: Deleted.

**Errors**

- `404`: `booking_page_not_found`: the person has no booking page with that id.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.deletePage()`](https://nextmail.sh/docs/sdk/reference/bookings#deletePage); Python [`bookings.delete_page()`](https://nextmail.sh/docs/python/reference/bookings#deletePage); Ruby [`bookings.delete_page`](https://nextmail.sh/docs/ruby/reference/bookings#deletePage); PHP [`bookings->deletePage`](https://nextmail.sh/docs/php/reference/bookings#deletePage); Go [`Bookings.DeletePage`](https://nextmail.sh/docs/go/reference/bookings#deletePage); Java [`bookings().deletePage`](https://nextmail.sh/docs/java/reference/bookings#deletePage); C# [`Bookings.DeletePageAsync`](https://nextmail.sh/docs/csharp/reference/bookings#deletePage); CLI [`nextmail bookings delete-page`](https://nextmail.sh/docs/cli/reference/bookings#bookings-delete-page); MCP [`deleteBookingPage`](https://nextmail.sh/docs/mcp/tools/bookings#deleteBookingPage).

### `PUT /booking-pages/{id}/background`

Upload the background image of a booking page

Uploads the photo that fills the public page behind the card, replacing the one there was, and switches `config.appearance.background` to `image`. Send the image itself as the body, not JSON, with its type in `Content-Type`. Up to 5 MB goes in; it is fitted and stored as WebP, and `config.appearance.backgroundImage` then holds its address. An animated image keeps its first frame.

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

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

**Path parameters**

- `id` (`string`, required): The booking page, such as `bkp_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /booking-pages` lists it.

**Request body**

Content type: `image/png`, `image/jpeg`, `image/webp`, `image/gif`.

`binary`

**Returns**

- `200` `BookingPage`: The page, showing the new image.

**Errors**

- `404`: `booking_page_not_found`: the person has no booking page with that id.
- `422`: `invalid_image` when the body is not an image of an accepted type, is too large or cannot be read. `capability_unsupported`: the key or app is limited to particular addresses.
- `502`: `image_not_stored`: the image was read but could not be stored. Try again.
- `503`: `image_busy`: the image service is saturated. Try again shortly.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.uploadBackground()`](https://nextmail.sh/docs/sdk/reference/bookings#uploadBackground); Python [`bookings.upload_background()`](https://nextmail.sh/docs/python/reference/bookings#uploadBackground); Ruby [`bookings.upload_background`](https://nextmail.sh/docs/ruby/reference/bookings#uploadBackground); PHP [`bookings->uploadBackground`](https://nextmail.sh/docs/php/reference/bookings#uploadBackground); Go [`Bookings.UploadBackground`](https://nextmail.sh/docs/go/reference/bookings#uploadBackground); Java [`bookings().uploadBackground`](https://nextmail.sh/docs/java/reference/bookings#uploadBackground); C# [`Bookings.UploadBackgroundAsync`](https://nextmail.sh/docs/csharp/reference/bookings#uploadBackground); CLI [`nextmail bookings upload-background`](https://nextmail.sh/docs/cli/reference/bookings#bookings-upload-background); MCP [`setBookingPageBackground`](https://nextmail.sh/docs/mcp/tools/bookings#setBookingPageBackground).

### `DELETE /booking-pages/{id}/background`

Remove the background image of a booking page

Deletes the stored background photo of a page. A page that showed it goes back to the `default` background, and one that showed a preset or a colour keeps it. Removing an image that is not set changes nothing, so a repeated call is safe.

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

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

**Path parameters**

- `id` (`string`, required): The booking page, such as `bkp_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /booking-pages` lists it.

**Returns**

- `200` `BookingPage`: The page, without the image.

**Errors**

- `404`: `booking_page_not_found`: the person has no booking page with that id.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.removeBackground()`](https://nextmail.sh/docs/sdk/reference/bookings#removeBackground); Python [`bookings.remove_background()`](https://nextmail.sh/docs/python/reference/bookings#removeBackground); Ruby [`bookings.remove_background`](https://nextmail.sh/docs/ruby/reference/bookings#removeBackground); PHP [`bookings->removeBackground`](https://nextmail.sh/docs/php/reference/bookings#removeBackground); Go [`Bookings.RemoveBackground`](https://nextmail.sh/docs/go/reference/bookings#removeBackground); Java [`bookings().removeBackground`](https://nextmail.sh/docs/java/reference/bookings#removeBackground); C# [`Bookings.RemoveBackgroundAsync`](https://nextmail.sh/docs/csharp/reference/bookings#removeBackground); CLI [`nextmail bookings remove-background`](https://nextmail.sh/docs/cli/reference/bookings#bookings-remove-background); MCP [`removeBookingPageBackground`](https://nextmail.sh/docs/mcp/tools/bookings#removeBookingPageBackground).

### `GET /booking-pages/{id}/times`

List the open times of a booking page

The start times a guest could book in a window, in order: the hours of the page with the calendar, other bookings, the gaps around meetings, the daily limit, the notice and the out of office periods taken out. A paused page still answers, and a page with a `problem` offers nothing. With `bookingId` they are the times that booking can move to with `POST /bookings/{id}/reschedule`.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Path parameters**

- `id` (`string`, required): The booking page, such as `bkp_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /booking-pages` lists it.

**Query parameters**

- `from` (`string`, format `date-time`): The start of the window. Defaults to now.
- `to` (`string`, format `date-time`): The end of the window, later than `from`. Defaults to 14 days after `from`, and counts for at most 62 days after it.
- `durationMinutes` (`integer`, at least 1): The meeting length in minutes, one of the `durations` of the page. Defaults to the shortest.
- `bookingId` (`string`, 1 to 64 characters): A booking on this page to find a new time for, such as `bkg_2b8d4f6a1c3e5079b6d8f0a2`. Its own time counts as free and the times are for its length, so `durationMinutes` is ignored.

**Returns**

- `200` `BookingTimes`: The open times.

**Errors**

- `404`: `booking_page_not_found`: the person has no booking page with that id. `booking_not_found`: the person has no booking with that id.
- `409`: `booking_ended`: the booking was already declined or cancelled.
- `422`: `invalid_parameter`: `to` is not later than `from`, or `durationMinutes` is not a length the page offers. `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.listTimes()`](https://nextmail.sh/docs/sdk/reference/bookings#listTimes); Python [`bookings.list_times()`](https://nextmail.sh/docs/python/reference/bookings#listTimes); Ruby [`bookings.list_times`](https://nextmail.sh/docs/ruby/reference/bookings#listTimes); PHP [`bookings->listTimes`](https://nextmail.sh/docs/php/reference/bookings#listTimes); Go [`Bookings.ListTimes`](https://nextmail.sh/docs/go/reference/bookings#listTimes); Java [`bookings().listTimes`](https://nextmail.sh/docs/java/reference/bookings#listTimes); C# [`Bookings.ListTimesAsync`](https://nextmail.sh/docs/csharp/reference/bookings#listTimes); CLI [`nextmail bookings list-times`](https://nextmail.sh/docs/cli/reference/bookings#bookings-list-times); MCP [`listBookingTimes`](https://nextmail.sh/docs/mcp/tools/bookings#listBookingTimes).

### `GET /bookings`

List bookings

The meetings guests booked on the pages of the person, or on some of them with `pageIds`. `q` searches the guest and the page, and `from` and `to` keep the meetings that start in a window. `upcoming` and `pending` come soonest first, `past` and `ended` latest first. One guest address holds at most 3 upcoming bookings on a page.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Query parameters**

- `view` (`string`, one of `"upcoming"`, `"pending"`, `"past"`, `"ended"`): Which bookings to list: `upcoming`, `pending`, `past` or `ended`. Defaults to `upcoming`.
- `pageId` (`string`, 1 to 64 characters): Only the bookings of this booking page, by its id. Left out, the bookings of every page of the person are listed.
- `pageIds` (`string`, up to 1625 characters): Only the bookings of these booking pages, at most 25 ids. Left out, every page of the person.
- `q` (`string`, up to 200 characters): Only the bookings whose guest name, guest email or page name contains this text, at most 200 characters. Case and accents are ignored.
- `from` (`string`, format `date-time`): Only the meetings that start at or after this instant, as a `Date` or an ISO 8601 string.
- `to` (`string`, format `date-time`): Only the meetings that start before this instant, later than `from`.
- `limit` (`integer`, at least 1, at most 100): Page size, from 1 to 100. The server defaults to 30.
- `cursor` (`string`, 1 to 256 characters): The `nextCursor` of the previous page, passed back as it came. Leave it out for the first page.

**Returns**

- `200` `BookingList`: A page of bookings.

**Errors**

- `400`: `invalid_cursor`.
- `404`: `booking_page_not_found`: the person has no booking page with that id.
- `422`: `invalid_parameter`: a query value is malformed, `pageIds` names too many pages, or `to` is not later than `from`. `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.list()`](https://nextmail.sh/docs/sdk/reference/bookings#list), [`nextmail.bookings.listAll()`](https://nextmail.sh/docs/sdk/reference/bookings#listAll), [`nextmail.bookings.iterate()`](https://nextmail.sh/docs/sdk/reference/bookings#iterate); Python [`bookings.list()`](https://nextmail.sh/docs/python/reference/bookings#list), [`bookings.list_all()`](https://nextmail.sh/docs/python/reference/bookings#listAll), [`bookings.iterate()`](https://nextmail.sh/docs/python/reference/bookings#iterate); Ruby [`bookings.list`](https://nextmail.sh/docs/ruby/reference/bookings#list), [`bookings.list_all`](https://nextmail.sh/docs/ruby/reference/bookings#listAll), [`bookings.iterate`](https://nextmail.sh/docs/ruby/reference/bookings#iterate); PHP [`bookings->list`](https://nextmail.sh/docs/php/reference/bookings#list), [`bookings->listAll`](https://nextmail.sh/docs/php/reference/bookings#listAll), [`bookings->iterate`](https://nextmail.sh/docs/php/reference/bookings#iterate); Go [`Bookings.List`](https://nextmail.sh/docs/go/reference/bookings#list), [`Bookings.ListAll`](https://nextmail.sh/docs/go/reference/bookings#listAll), [`Bookings.Iterate`](https://nextmail.sh/docs/go/reference/bookings#iterate); Java [`bookings().list`](https://nextmail.sh/docs/java/reference/bookings#list), [`bookings().listAll`](https://nextmail.sh/docs/java/reference/bookings#listAll), [`bookings().iterate`](https://nextmail.sh/docs/java/reference/bookings#iterate); C# [`Bookings.ListAsync`](https://nextmail.sh/docs/csharp/reference/bookings#list), [`Bookings.ListAllAsync`](https://nextmail.sh/docs/csharp/reference/bookings#listAll), [`Bookings.IterateAsync`](https://nextmail.sh/docs/csharp/reference/bookings#iterate); CLI [`nextmail bookings list`](https://nextmail.sh/docs/cli/reference/bookings#bookings-list); MCP [`listBookings`](https://nextmail.sh/docs/mcp/tools/bookings#listBookings).

### `GET /bookings/{id}`

Read a booking

One booking with the guest, their answers, the calendar event it is and how it ended if it did. A booking follows its calendar event, so a meeting moved or cancelled in the calendar reads as moved or cancelled here.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Path parameters**

- `id` (`string`, required): The booking, such as `bkg_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /bookings` lists it.

**Returns**

- `200` `Booking`: The booking.

**Errors**

- `404`: `booking_not_found`: the person has no booking with that id.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.get()`](https://nextmail.sh/docs/sdk/reference/bookings#get); Python [`bookings.get()`](https://nextmail.sh/docs/python/reference/bookings#get); Ruby [`bookings.get`](https://nextmail.sh/docs/ruby/reference/bookings#get); PHP [`bookings->get`](https://nextmail.sh/docs/php/reference/bookings#get); Go [`Bookings.Get`](https://nextmail.sh/docs/go/reference/bookings#get); Java [`bookings().get`](https://nextmail.sh/docs/java/reference/bookings#get); C# [`Bookings.GetAsync`](https://nextmail.sh/docs/csharp/reference/bookings#get); CLI [`nextmail bookings get`](https://nextmail.sh/docs/cli/reference/bookings#bookings-get); MCP [`getBooking`](https://nextmail.sh/docs/mcp/tools/bookings#getBooking).

### `POST /bookings/{id}/approve`

Approve a booking

Confirms a booking that waits for approval, on a page whose `config.approval` is true. The hold on the calendar becomes a confirmed meeting. The guest is told by email, sent from the address of the page with the calendar invitation or its cancellation attached.

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

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

**Path parameters**

- `id` (`string`, required): The booking, such as `bkg_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /bookings` lists it.

**Returns**

- `200` `Booking`: The booking, confirmed.

**Errors**

- `404`: `booking_not_found`: the person has no booking with that id.
- `409`: `booking_not_pending`: the booking is not waiting for approval. `booking_ended`: its time has passed.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.approve()`](https://nextmail.sh/docs/sdk/reference/bookings#approve); Python [`bookings.approve()`](https://nextmail.sh/docs/python/reference/bookings#approve); Ruby [`bookings.approve`](https://nextmail.sh/docs/ruby/reference/bookings#approve); PHP [`bookings->approve`](https://nextmail.sh/docs/php/reference/bookings#approve); Go [`Bookings.Approve`](https://nextmail.sh/docs/go/reference/bookings#approve); Java [`bookings().approve`](https://nextmail.sh/docs/java/reference/bookings#approve); C# [`Bookings.ApproveAsync`](https://nextmail.sh/docs/csharp/reference/bookings#approve); CLI [`nextmail bookings approve`](https://nextmail.sh/docs/cli/reference/bookings#bookings-approve); MCP [`approveBooking`](https://nextmail.sh/docs/mcp/tools/bookings#approveBooking).

### `POST /bookings/{id}/decline`

Decline a booking

Turns down a booking that waits for approval and frees its time. The guest is told by email, sent from the address of the page with the calendar invitation or its cancellation attached.

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

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

**Path parameters**

- `id` (`string`, required): The booking, such as `bkg_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /bookings` lists it.

**Request body**

- `reason` (`string`, nullable, up to 500 characters): A sentence for the guest, at most 500 characters, included in the email they get.

**Returns**

- `200` `Booking`: The booking, declined.

**Errors**

- `404`: `booking_not_found`: the person has no booking with that id.
- `409`: `booking_not_pending`: the booking is not waiting for approval.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.decline()`](https://nextmail.sh/docs/sdk/reference/bookings#decline); Python [`bookings.decline()`](https://nextmail.sh/docs/python/reference/bookings#decline); Ruby [`bookings.decline`](https://nextmail.sh/docs/ruby/reference/bookings#decline); PHP [`bookings->decline`](https://nextmail.sh/docs/php/reference/bookings#decline); Go [`Bookings.Decline`](https://nextmail.sh/docs/go/reference/bookings#decline); Java [`bookings().decline`](https://nextmail.sh/docs/java/reference/bookings#decline); C# [`Bookings.DeclineAsync`](https://nextmail.sh/docs/csharp/reference/bookings#decline); CLI [`nextmail bookings decline`](https://nextmail.sh/docs/cli/reference/bookings#bookings-decline); MCP [`declineBooking`](https://nextmail.sh/docs/mcp/tools/bookings#declineBooking).

### `POST /bookings/{id}/cancel`

Cancel a booking

Cancels a meeting that has not ended yet and cancels its calendar event. A booking that still waits for approval is declined instead. The guest is told by email, sent from the address of the page with the calendar invitation or its cancellation attached.

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

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

**Path parameters**

- `id` (`string`, required): The booking, such as `bkg_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /bookings` lists it.

**Request body**

- `reason` (`string`, nullable, up to 500 characters): A sentence for the guest, at most 500 characters, included in the email they get.

**Returns**

- `200` `Booking`: The booking, cancelled.

**Errors**

- `404`: `booking_not_found`: the person has no booking with that id.
- `409`: `booking_ended`: the booking was already declined or cancelled, or the meeting is over.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.cancel()`](https://nextmail.sh/docs/sdk/reference/bookings#cancel); Python [`bookings.cancel()`](https://nextmail.sh/docs/python/reference/bookings#cancel); Ruby [`bookings.cancel`](https://nextmail.sh/docs/ruby/reference/bookings#cancel); PHP [`bookings->cancel`](https://nextmail.sh/docs/php/reference/bookings#cancel); Go [`Bookings.Cancel`](https://nextmail.sh/docs/go/reference/bookings#cancel); Java [`bookings().cancel`](https://nextmail.sh/docs/java/reference/bookings#cancel); C# [`Bookings.CancelAsync`](https://nextmail.sh/docs/csharp/reference/bookings#cancel); CLI [`nextmail bookings cancel`](https://nextmail.sh/docs/cli/reference/bookings#bookings-cancel); MCP [`cancelBooking`](https://nextmail.sh/docs/mcp/tools/bookings#cancelBooking).

### `POST /bookings/{id}/reschedule`

Reschedule a booking

Moves a meeting that has not started to a new time, keeping its length, and moves its calendar event with it. The time has to be open on the page, as `GET /booking-pages/{id}/times` lists the times with `bookingId`; the page may be paused, and the cut-off for guests does not apply to you. A booking that waits for approval is confirmed at the new time. The guest is told by email, sent from the address of the page with the calendar invitation or its cancellation attached. You get a copy too, unless `config.notifyHost` is false.

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

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

**Path parameters**

- `id` (`string`, required): The booking, such as `bkg_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /bookings` lists it.

**Request body**

- `start` (`string`, required, format `date-time`): The new start as an ISO 8601 instant. It has to be one of the open times of the page for this booking, as `GET /booking-pages/{id}/times` lists them with `bookingId`. The meeting keeps its length.
- `reason` (`string`, nullable, up to 500 characters): A sentence for the guest, at most 500 characters, included in the email about the new time.

**Returns**

- `200` `Booking`: The booking at its new time.

**Errors**

- `404`: `booking_not_found`: the person has no booking with that id.
- `409`: `booking_time_unavailable`: that time is not open on the page for this booking. `booking_ended`: the booking was declined or cancelled, or the meeting has started.
- `422`: `invalid_parameter`: `start` is missing or malformed. `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.reschedule()`](https://nextmail.sh/docs/sdk/reference/bookings#reschedule); Python [`bookings.reschedule()`](https://nextmail.sh/docs/python/reference/bookings#reschedule); Ruby [`bookings.reschedule`](https://nextmail.sh/docs/ruby/reference/bookings#reschedule); PHP [`bookings->reschedule`](https://nextmail.sh/docs/php/reference/bookings#reschedule); Go [`Bookings.Reschedule`](https://nextmail.sh/docs/go/reference/bookings#reschedule); Java [`bookings().reschedule`](https://nextmail.sh/docs/java/reference/bookings#reschedule); C# [`Bookings.RescheduleAsync`](https://nextmail.sh/docs/csharp/reference/bookings#reschedule); CLI [`nextmail bookings reschedule`](https://nextmail.sh/docs/cli/reference/bookings#bookings-reschedule); MCP [`rescheduleBooking`](https://nextmail.sh/docs/mcp/tools/bookings#rescheduleBooking).

### `POST /bookings/{id}/resend`

Send the booking email again

Sends the guest the email that matches where the booking stands now: the request, the confirmation with its invitation, or the notice that it was declined or cancelled. Use it when `guestMailFailed` is true.

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

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

**Path parameters**

- `id` (`string`, required): The booking, such as `bkg_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /bookings` lists it.

**Returns**

- `200` `Booking`: The booking, with `guestMailFailed` as it is after the send.

**Errors**

- `404`: `booking_not_found`: the person has no booking with that id.
- `422`: `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.resendEmail()`](https://nextmail.sh/docs/sdk/reference/bookings#resendEmail); Python [`bookings.resend_email()`](https://nextmail.sh/docs/python/reference/bookings#resendEmail); Ruby [`bookings.resend_email`](https://nextmail.sh/docs/ruby/reference/bookings#resendEmail); PHP [`bookings->resendEmail`](https://nextmail.sh/docs/php/reference/bookings#resendEmail); Go [`Bookings.ResendEmail`](https://nextmail.sh/docs/go/reference/bookings#resendEmail); Java [`bookings().resendEmail`](https://nextmail.sh/docs/java/reference/bookings#resendEmail); C# [`Bookings.ResendEmailAsync`](https://nextmail.sh/docs/csharp/reference/bookings#resendEmail); CLI [`nextmail bookings resend-email`](https://nextmail.sh/docs/cli/reference/bookings#bookings-resend-email); MCP [`resendBookingEmail`](https://nextmail.sh/docs/mcp/tools/bookings#resendBookingEmail).

### `GET /bookings/analytics`

Read booking analytics

The numbers behind the Analytics tabs of Booking: the bookings guests made over a window, what became of them, the pages and weekdays they went to, and the meetings still to come right now, for every page of the person or for the pages `pageIds` names. A booking counts in the window it was made in, whatever its meeting time. A booking page belongs to one person. An API key acts as the workspace owner and reaches the pages of the owner, and a connected app reaches the pages of the person who connected it.

Requires the `calendar:read` scope.

- Scopes: `calendar:read`.

**Query parameters**

- `pageId` (`string`, 1 to 64 characters): Count only the bookings of this booking page, such as `bkp_5c1e9a7b3d2f48e6a0b4c7d1`, the same as `pageIds` with one id.
- `pageIds` (`string`, up to 1625 characters): Count only these booking pages, at most 25, such as `['bkp_5c1e9a7b3d2f48e6a0b4c7d1']`. Every page of the person when left out.
- `days` (`integer`, at least 1, at most 1095): How far back to look, from 1 to 1095, defaulting to 30.
- `minutes` (`integer`, at least 1, at most 1576800): The window in minutes, from 1 to 1576800, which wins over `days` when both are sent.
- `grain` (`string`, one of `"minute"`, `"hour"`, `"day"`): Bucket width: `minute`, `hour` or `day`, defaulting to `day`.
- `offsetMinutes` (`integer`, at least -840, at most 840): Minutes east of UTC to cut the buckets and the weekdays in, from -840 to 840, defaulting to 0. Pass `-new Date().getTimezoneOffset()` for the local zone.

**Returns**

- `200` `BookingAnalytics`: The window, the totals and the breakdowns.

**Errors**

- `404`: `booking_page_not_found`: the person has no booking page with that id.
- `422`: `invalid_parameter`: a query value is out of range, or `pageIds` names too many pages. `capability_unsupported`: the key or app is limited to particular addresses.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.bookings.analytics()`](https://nextmail.sh/docs/sdk/reference/bookings#analytics); Python [`bookings.analytics()`](https://nextmail.sh/docs/python/reference/bookings#analytics); Ruby [`bookings.analytics`](https://nextmail.sh/docs/ruby/reference/bookings#analytics); PHP [`bookings->analytics`](https://nextmail.sh/docs/php/reference/bookings#analytics); Go [`Bookings.Analytics`](https://nextmail.sh/docs/go/reference/bookings#analytics); Java [`bookings().analytics`](https://nextmail.sh/docs/java/reference/bookings#analytics); C# [`Bookings.AnalyticsAsync`](https://nextmail.sh/docs/csharp/reference/bookings#analytics); CLI [`nextmail bookings analytics`](https://nextmail.sh/docs/cli/reference/bookings#bookings-analytics); MCP [`getBookingAnalytics`](https://nextmail.sh/docs/mcp/tools/bookings#getBookingAnalytics).

### Objects

#### `Booking`

`object`

- `object` (`string`, required, one of `"booking"`)
- `id` (`string`, required): The id, which starts with `bkg_`.
- `pageId` (`string`, required): The booking page it was made on.
- `pageName` (`string`, required)
- `status` (`string`, required, one of `"pending"`, `"confirmed"`, `"declined"`, `"cancelled"`): `pending` while it waits for approval, `confirmed` once the meeting stands, `declined` when a request was turned down, and `cancelled` when a confirmed meeting was called off.
- `expired` (`boolean`, required): True for a request nobody answered before its time came.
- `past` (`boolean`, required): True once the meeting is over.
- `start` (`string`, required, format `date-time`): When the meeting starts.
- `end` (`string`, required, format `date-time`): When it ends.
- `durationMinutes` (`integer`, required)
- `guest` (`object`, required)
  - `name` (`string`, required)
  - `email` (`string`, required, format `email`)
  - `timezone` (`string`, required): The time zone the guest booked in, which their emails use.
- `guests` (`string[]`, required): The other people invited to the meeting: the ones the guest added when booking, and anyone added to the calendar event since. Empty when there are none.
- `answers` (`object[]`, required): What the guest answered to the questions of the page.
  - `id` (`string`, required): The `id` of the question.
  - `label` (`string`, required): The question as it was asked.
  - `kind` (`string`, required, one of `"text"`, `"long-text"`, `"phone"`, `"choice"`, `"checkbox"`)
  - `value` (`string`, required): The answer. A `checkbox` answers `yes` or `no`.
- `location` (`string`, required): Where the meeting happens, as the guest was told: the link, the phone number or the address.
- `eventId` (`string`, required, nullable): The calendar event of the booking, as `GET /calendar/events/{id}` reads it. Null once the booking ended and its event was removed.
- `endedBy` (`string`, required, nullable, one of `"host"`, `"guest"`): Who declined or cancelled it.
- `endReason` (`string`, required, nullable): The reason they gave.
- `rescheduleCount` (`integer`, required, at least 0): How often the meeting was moved.
- `guestMailFailed` (`boolean`, required): True when the last email to the guest could not be sent. `POST /bookings/{id}/resend` tries again.
- `createdAt` (`string`, required, format `date-time`): When the guest booked.

#### `BookingAnalytics`

`object`

- `object` (`string`, required, one of `"booking_analytics"`)
- `pageId` (`string`, required, nullable): The booking page the numbers are for when they are for exactly one, or null.
- `pageIds` (`string[]`, required): The booking pages the numbers are for, or an empty list for every page of the person.
- `since` (`string`, required, format `date-time`): The start of the oldest bucket, where the window begins.
- `until` (`string`, required, format `date-time`): Now, where the window ends.
- `grain` (`string`, required, one of `"minute"`, `"hour"`, `"day"`)
- `offsetMinutes` (`integer`, required): The offset the buckets were cut in.
- `totals` (`object`, required)
  - `booked` (`integer`, required, at least 0): Bookings made in the window, whatever became of them.
  - `confirmed` (`integer`, required, at least 0): Of those, the meetings that stand, held or still to come.
  - `pending` (`integer`, required, at least 0): Of those, the requests still waiting for an answer.
  - `expired` (`integer`, required, at least 0): Of those, the requests nobody answered before their time came.
  - `declined` (`integer`, required, at least 0): Of those, the requests the host turned down.
  - `cancelled` (`integer`, required, at least 0): Of those, the meetings called off.
  - `cancelledByGuest` (`integer`, required, at least 0): Cancelled by the guest.
  - `cancelledByHost` (`integer`, required, at least 0): Cancelled by the host.
  - `rescheduled` (`integer`, required, at least 0): Of those, the meetings moved at least once.
  - `minutesBooked` (`integer`, required, at least 0): The minutes of the confirmed meetings.
  - `cancellationRate` (`number`, required, nullable, at least 0, at most 1): Cancelled divided by booked, or null when nothing was booked.
- `upcoming` (`object`, required): The calendar right now, whatever the window.
  - `confirmed` (`integer`, required, at least 0): Confirmed meetings that have not ended.
  - `waiting` (`integer`, required, at least 0): Requests that wait for approval and whose time has not come.
  - `nextStart` (`string`, required, nullable, format `date-time`): When the next confirmed meeting starts, or null when none is coming.
- `series` (`object[]`, required): Bookings made per bucket, oldest first. A bucket with nothing in it has no entry, so a chart must fill the gaps. `bucket` is `YYYY-MM-DD`, `YYYY-MM-DDTHH` or `YYYY-MM-DDTHH:MM` by `grain`.
  - `bucket` (`string`, required)
  - `booked` (`integer`, required, at least 0): Bookings made in the bucket.
  - `cancelled` (`integer`, required, at least 0): Of those, the ones called off since.
- `pages` (`object[]`, required): The pages that got bookings in the window, most first, at most 10.
  - `pageId` (`string`, required)
  - `name` (`string`, required)
  - `booked` (`integer`, required, at least 0): Bookings made on the page in the window.
  - `cancelled` (`integer`, required, at least 0): Of those, the ones called off since.
- `weekdays` (`object[]`, required): The meetings booked in the window that stand or wait for approval, by the weekday they fall on, Sunday (0) to Saturday (6), always seven entries.
  - `weekday` (`integer`, required, at least 0, at most 6)
  - `meetings` (`integer`, required, at least 0): Meetings on that weekday.

#### `BookingList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`Booking[]`)
- `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.

#### `BookingPage`

`object`

- `object` (`string`, required, one of `"booking_page"`)
- `id` (`string`, required): The id, which starts with `bkp_`.
- `slug` (`string`, required): The last part of the public link, `/book/<slug>`: lowercase letters, digits and hyphens. Left out, it is made from the name. It is unique across Nextmail.
- `name` (`string`, required): What the page is called, shown to guests as its heading, such as `Intro call`.
- `status` (`string`, required, one of `"active"`, `"paused"`): `active` takes bookings. `paused` keeps the link working but offers no times.
- `url` (`string`, required): The public link to hand to guests.
- `problem` (`string`, required, nullable, one of `"sender"`, `"host"`, `"hours"`): What stops the page from taking bookings, or null: `sender` when `config.fromEmail` can no longer send, `hours` when no hours are open at all, and `host` when the person left the workspace.
- `config` (`BookingPageConfig`, required)
- `counts` (`object`, required)
  - `upcoming` (`integer`, required, at least 0): Confirmed bookings that have not started.
  - `pending` (`integer`, required, at least 0): Bookings that wait for approval.
- `away` (`object[]`, required): The out of office periods of `config.fromEmail` that are running or still to come. While `config.busy.outOfOffice` is true the page offers no times inside them.
  - `address` (`string`, required): The address, or the catch-all such as `*@example.com`, that is out of office.
  - `startsAt` (`string`, required, format `date-time`): When the period starts.
  - `endsAt` (`string`, required, nullable, format `date-time`): When it ends, or null while it has no end date.
- `createdAt` (`string`, required, format `date-time`): When the page was created.
- `updatedAt` (`string`, required, format `date-time`): When the page last changed.

#### `BookingPageConfig`

`object`

- `description` (`string`, required, up to 2000 characters): Text shown under the name of the page. Basic Markdown works: bold, italic, links and lists.
- `hostName` (`string`, required, up to 80 characters): The name guests see as the person they meet. Defaults to the name of the account.
- `durations` (`integer[]`, required, 1 to 4 items): The meeting lengths a guest can pick, in minutes, each a multiple of 5 between 5 and 720.
- `approval` (`boolean`, required): True holds each new booking as a request until it is approved or declined. False confirms it at once.
- `fromEmail` (`string`, required, up to 320 characters): The address the booking emails are sent from and the calendar events are organised by. It has to be one the owner of the page may send from.
- `notifyHost` (`boolean`, required): Whether that address gets an email about each new, moved or cancelled booking.
- `questions` (`object[]`, required, up to 10 items): What the guest is asked besides their name and email, at most 10.
  - `id` (`string`, required, pattern `^[a-z0-9]{4,16}$`): A stable key for the answers: 4 to 16 lowercase letters and digits, unique on the page. `name`, `email`, `phone`, `timezone` and `start` are taken.
  - `kind` (`string`, required, one of `"text"`, `"long-text"`, `"phone"`, `"choice"`, `"checkbox"`): `text`, `long-text`, `phone`, `choice` (one of `options`) or `checkbox`.
  - `label` (`string`, required, 1 to 120 characters)
  - `required` (`boolean`, required)
  - `options` (`string[]`, required, up to 12 items): The answers of a `choice` question, at least two. Empty for the other kinds.
  - `placeholder` (`string`, up to 160 characters): Example text shown in the empty field of a `text`, `long-text` or `phone` question, such as `Anything we should know before the meeting?`. Up to 160 characters, empty for none. A `choice` or `checkbox` question ignores it.
- `confirmation` (`string`, required, up to 1000 characters): Text shown to the guest after booking, and added to the confirmation email.
- `redirectUrl` (`string`, required, up to 2000 characters): An `https://` page to send the guest to after booking, or empty.
- `extraGuests` (`integer`, at least 0, at most 10, default `0`): How many other people a guest may add to a booking, 0 to 10. Each one gets the invitation and every later change. Defaults to 0, which hides the field.
- `reminders` (`object`, default `{"guest":[1440],"host":[10]}`): When the guest is emailed a reminder and when the host is reminded, each a list of minutes before the start.
  - `guest` (`integer[]`, required, up to 3 items): Minutes before the start to email the guest a reminder, at most 3, each one of 10, 30, 60, 120, 1440, 2880, 10080. Defaults to one day before. An empty list sends none.
  - `host` (`integer[]`, required, up to 3 items): Minutes before the start the host is reminded by the alarm on the meeting in their calendar, at most 3, each one of 0, 5, 10, 15, 30, 60, 1440. Defaults to 10. It applies to meetings booked after it changes.
- `location` (`object`, required): Where the meeting happens.
  - `kind` (`string`, required, one of `"video"`, `"phone"`, `"in-person"`, `"none"`): `video` with a fixed link in `value`, `phone` (the guest is asked for a number), `in-person` with the address in `value`, or `none`.
  - `value` (`string`, required, up to 500 characters): The `https://` link of a `video` meeting or the address of an `in-person` one.
- `availability` (`object`, required): When the page offers times, before the calendar is taken out.
  - `timezone` (`string`, required, 1 to 64 characters): The IANA time zone the hours below are read in.
  - `weekly` (`object[][]`, required, 7 to 7 items): Seven lists, Sunday first, of the hours open on that weekday. An empty list closes the day.
    - `start` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range opens, so `540` is 09:00.
    - `end` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range closes, later than `start`.
  - `overrides` (`object[]`, required, up to 180 items): Dates with their own hours, at most 180. `date` is `YYYY-MM-DD` in the time zone of the page, and an empty `ranges` closes that date.
    - `date` (`string`, required)
    - `ranges` (`object[]`, required, up to 6 items)
      - `start` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range opens, so `540` is 09:00.
      - `end` (`integer`, required, at least 0, at most 1440): Minutes after midnight the range closes, later than `start`.
- `rules` (`object`, required): The limits on which of the open hours are offered.
  - `noticeMinutes` (`integer`, required, at least 0, at most 43200): How many minutes ahead a booking has to be made.
  - `horizonDays` (`integer`, required, at least 1, at most 365): How many days ahead the page offers times, up to 365.
  - `intervalMinutes` (`integer`, required, nullable): Minutes between two start times, one of 5, 10, 15, 20, 30, 45, 60, 90, 120. Null steps by the length of the meeting.
  - `bufferBeforeMinutes` (`integer`, required, at least 0, at most 240): Minutes kept free before every meeting, up to 240.
  - `bufferAfterMinutes` (`integer`, required, at least 0, at most 240): Minutes kept free after every meeting, up to 240.
  - `dailyLimit` (`integer`, required, nullable, at least 1, at most 50): The most bookings this page takes on one day, up to 50. Null for no limit.
- `appearance` (`object`, required): How the public page looks.
  - `accent` (`string`, required, pattern `^#[0-9a-f]{6}$`): The colour of buttons and the picked day, as `#rrggbb`.
  - `theme` (`string`, required, one of `"auto"`, `"light"`, `"dark"`): `auto` follows the device of the guest, or force `light` or `dark`.
  - `showAvatar` (`boolean`, required)
  - `background` (`string`, default `"default"`): What fills the page behind the card: `default`, one of the presets `dusk`, `mist`, `sand`, `night`, `meadow`, `dots`, `brush`, `trail`, `ember`, `canvas`, `bloom`, `field`, `wanderer` and `gold`, `image` for the uploaded background image, or a colour as `#rrggbb`. Defaults to `default`.
  - `fonts` (`object`, default `{"primary":null,"secondary":null}`): The typefaces of the public page: `primary` for its text and `secondary` for its title. Each is one of the brand fonts the workspace appearance offers, or null for the standard font.
    - `primary` (`string`, nullable, one of `"system"`, `"arial"`, `"helvetica"`, `"verdana"`, `"tahoma"`, `"trebuchet-ms"`, `"georgia"`, `"times-new-roman"`, `"courier-new"`, `"dm-sans"`, `"inter"`, `"roboto"`, `"open-sans"`, `"lato"`, `"montserrat"`, `"poppins"`, `"nunito"`, `"work-sans"`, `"source-sans-3"`, `"ibm-plex-sans"`, `"merriweather"`, `"playfair-display"`, `"instrument-serif"`, `"jetbrains-mono"`, `"dm-mono"`, `"geist-mono"`, default `null`): The font of the text, such as `inter`. Null uses the standard font.
    - `secondary` (`string`, nullable, one of `"system"`, `"arial"`, `"helvetica"`, `"verdana"`, `"tahoma"`, `"trebuchet-ms"`, `"georgia"`, `"times-new-roman"`, `"courier-new"`, `"dm-sans"`, `"inter"`, `"roboto"`, `"open-sans"`, `"lato"`, `"montserrat"`, `"poppins"`, `"nunito"`, `"work-sans"`, `"source-sans-3"`, `"ibm-plex-sans"`, `"merriweather"`, `"playfair-display"`, `"instrument-serif"`, `"jetbrains-mono"`, `"dm-mono"`, `"geist-mono"`, default `null`): The font of the title, such as `instrument-serif`. Null keeps the title in the font of the text.
  - `backgroundImage` (`string`, nullable, up to 2000 characters, default `null`): The address of the uploaded background image, or null. Read only: upload one with `PUT /booking-pages/{id}/background` and remove it with `DELETE` on the same path.
- `guestChanges` (`object`, required): What a guest may do from the link in their emails.
  - `cancel` (`boolean`, required)
  - `reschedule` (`boolean`, required)
  - `cutoffMinutes` (`integer`, required, at least 0, at most 20160): How many minutes before the meeting those changes close.
- `busy` (`object`, required): What counts as busy besides the events the person made and the bookings they already have.
  - `addresses` (`string[]`, required, nullable, up to 50 items): The addresses whose invitations block time unless declined. Null checks every address the person holds.
  - `subscriptions` (`boolean`, required): Whether events from calendars the person subscribed to block time.
  - `outOfOffice` (`boolean`, default `true`): Whether the page offers no times while `fromEmail` is out of office. Defaults to true.
- `seo` (`object`, default `{}`): How the public page presents itself to browsers and search engines.
  - `title` (`string`, up to 120 characters, default `""`): The title of the browser tab and of a search result. Empty uses the name of the page and the host.
  - `description` (`string`, up to 300 characters, default `""`): The summary under the title in a search result. Empty uses the start of the description.
  - `indexable` (`boolean`, default `false`): Whether search engines may list the page. False, the default, asks them not to.

#### `BookingPageList`

`object`

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

#### `BookingTimes`

`object`

- `object` (`string`, required, one of `"booking_times"`)
- `pageId` (`string`, required)
- `timezone` (`string`, required): The time zone of the page.
- `durationMinutes` (`integer`, required): The meeting length the times are for.
- `times` (`string[]`, required): Every open start time in the window, in order.

#### `DeletedBookingPage`

`object`

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