Skip to the documentation
Python

nextmail.bookings

Every method in this namespace: its signature, its parameters, what it returns and an example.

Methods

Public links where somebody books a meeting on a person's calendar: create a booking page, change its hours, questions and rules, pause or delete it, read the times it offers, list the meetings guests booked, and approve, decline or cancel one. An API key acts for the workspace owner, and an app for the person who connected it.

bookings.list_pages()

List the booking pages of the person

Scopescalendar:read
Signature
def list_pages(    *,    q: str | None = None,    status: BookingPageStatus | None = None,    since: datetime | str | None = None,    until: datetime | str | None = None,    sort: BookingPageSort | None = None,    api_key: str | None = None,    timeout: float | None = None,) -> builtins.list[BookingPageResource]

Returns the booking pages of the person, oldest first unless sort= says otherwise. q= searches the name and the link, status= keeps the active or the paused pages, and since= and until= keep the pages made in a window. A booking page is a public link, /book/<slug>, where somebody picks a free time and books a meeting on the calendar of that person. Each page comes with its settings in config, the link to hand to guests in url, and in counts how many of its bookings are upcoming and how many wait for approval.

status is active while the page takes bookings and paused while its link works but offers no times. problem says what stops a page from taking bookings and is None when nothing does. away lists the out of office periods that close the page. A person holds at most 25 pages, so the list comes whole and is never paged.

Parameters

qstr

Only the pages whose name or link contains this text, at most 200 characters. Case and accents are ignored.

statusBookingPageStatus

active for the pages that take bookings, paused for the ones that do not. Left out, both.

sincedatetime | str

Only the pages made at or after this instant, as a datetime or an ISO 8601 string.

untildatetime | str

Only the pages made before this instant, later than since=.

sortBookingPageSort

oldest (the default) or newest by when the page was made, name from A to Z, or upcoming with the most upcoming meetings first. BOOKING_PAGE_SORTS holds the values.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

list[BookingPageResource]. Each item has id, slug, name, status, url, problem, config, counts, away, createdAt and updatedAt.

Example

from nextmail import nextmail pages = nextmail.bookings.list_pages() for page in pages:    print(page['name'], page['url'], page['status'], page['counts']['upcoming'])

Notes

  • 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.

  • problem is sender when config.fromEmail can no longer send, hours when no hours are open at all, and host when the person left the workspace.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • An until= that is not later than since= is 422 invalid_parameter.

Also available in

API
GET /booking-pages
TypeScript
nextmail.bookings.listPages()
Ruby
bookings.list_pages
PHP
bookings->listPages
Go
Bookings.ListPages
Java
bookings().listPages
C#
Bookings.ListPagesAsync
CLI
nextmail bookings list-pages

bookings.get_page()

Read one booking page by id

Scopescalendar:read
Signature
def get_page(    id: str,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingPageResource

Looks up a single booking page and returns it in the same shape as a row of list_pages, with every setting in config: the meeting lengths, where the meeting happens, the weekly hours and the dates with their own hours, the notice, the buffers and the daily limit, whether a booking waits for approval, the address its emails come from, the questions a guest is asked, how the page looks and what a guest may change afterwards.

config.availability.weekly holds seven lists, Sunday first, of the hours open on that weekday, each as minutes after midnight in config.availability.timezone. problem says what stops the page from taking bookings, and away lists 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.

Parameters

idstrRequired

Booking page id such as bkp_5c1e9a7b3d2f48e6a0b4c7d1, as list_pages returns it.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingPageResource with id, slug, name, status, url, problem, config, counts, away, createdAt and updatedAt.

Example

from nextmail import nextmail page = nextmail.bookings.get_page('bkp_5c1e9a7b3d2f48e6a0b4c7d1') print(page['url'], page['config']['durations'], page['config']['availability']['timezone'])print(page['problem'] or 'takes bookings')

Notes

  • A missing page raises NextmailApiError with is_not_found set to True and code booking_page_not_found. A page that belongs to somebody else in the workspace is missing too.

  • 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.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

Also available in

API
GET /booking-pages/{id}
TypeScript
nextmail.bookings.getPage()
Ruby
bookings.get_page
PHP
bookings->getPage
Go
Bookings.GetPage
Java
bookings().getPage
C#
Bookings.GetPageAsync
CLI
nextmail bookings get-page

bookings.create_page()

Create a booking page

Scopescalendar:writeemails:send
Signature
def create_page(    body: BookingPageCreate,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingPageResource

Creates a booking page and returns it as it is stored. The page takes bookings at once, at the link in url. Only name is required: the page starts with weekdays from 09:00 to 17:00, 30 minute meetings, four hours of notice, times up to 60 days ahead and the first address the person may send from. Anything in config replaces that default, and what it leaves out keeps it.

slug is the last part of the public link, /book/<slug>. Left out, it is made from the name. timezone says which time zone the working hours are read in when config.availability.timezone is not sent.

The times a page offers are its working hours 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 organised by config.fromEmail, and the guest is told by email from that address, so the call needs emails:send beside calendar:write.

Parameters

body['name']strRequired

What the page is called, shown to guests as its heading, such as Intro call. Trimmed, 1 to 80 characters.

body['slug']str

The last part of the public link: 3 to 60 lowercase letters and digits, with single hyphens between words. It is unique across Nextmail. Left out, it is made from the name.

body['timezone']str

The IANA time zone the working hours are read in, such as Europe/Berlin, when config.availability.timezone is not sent. Defaults to UTC.

body['config']['description']str

Text shown under the name of the page, up to 2,000 characters. Basic Markdown works: bold, italic, links and lists. Defaults to none.

body['config']['hostName']str

The name guests see as the person they meet, up to 80 characters. Defaults to the name of the account.

body['config']['durations']list[int]

The meeting lengths a guest can pick, in minutes: 1 to 4 of them, each a multiple of 5 between 5 and 720. Defaults to [30].

body['config']['location']['kind']BookingLocationKind

Where the meeting happens: video with a fixed link in value, phone, where the guest is asked for a number, in-person with the address in value, or none. Defaults to none.

body['config']['location']['value']str

The https:// link of a video meeting or the address of an in-person one, up to 500 characters. It is dropped for phone and none.

body['config']['availability']['timezone']str

The IANA time zone the hours of the page are read in. Defaults to timezone.

body['config']['availability']['weekly']list[list[BookingTimeRange]]

Seven lists, Sunday first, of the hours open on that weekday. Each range is a dict with start and end in minutes after midnight, so {'start': 540, 'end': 1020} is 09:00 to 17:00. An empty list closes the day, and a day takes at most 6 ranges. Defaults to 09:00 to 17:00 from Monday to Friday.

body['config']['availability']['overrides']list[BookingDateOverride]

Dates with their own hours, at most 180, each a dict with date and ranges. date is YYYY-MM-DD in the time zone of the page, and an empty ranges closes that date. Defaults to none.

body['config']['rules']['noticeMinutes']int

How many minutes ahead a booking has to be made, from 0 to 43,200. Defaults to 240.

body['config']['rules']['horizonDays']int

How many days ahead the page offers times, from 1 to 365. Defaults to 60.

body['config']['rules']['intervalMinutes']int | None

Minutes between two start times: 5, 10, 15, 20, 30, 45, 60, 90 or 120. None, the default, steps by the length of the meeting.

body['config']['rules']['bufferBeforeMinutes']int

Minutes kept free before every meeting, from 0 to 240. Defaults to 0.

body['config']['rules']['bufferAfterMinutes']int

Minutes kept free after every meeting, from 0 to 240. Defaults to 0.

body['config']['rules']['dailyLimit']int | None

The most bookings the page takes on one day, from 1 to 50. None, the default, sets no limit.

body['config']['approval']bool

True holds each new booking as a request until approve or decline answers it. False, the default, confirms it at once.

body['config']['fromEmail']str

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. Defaults to the first such address.

body['config']['notifyHost']bool

Whether fromEmail gets an email about each new, moved or cancelled booking. Defaults to True.

body['config']['questions']list[BookingQuestion]

What the guest is asked besides their name and email, at most 10, each a dict with id, kind, label, required, options and placeholder. id is a stable key for the answers: 4 to 16 lowercase letters and digits, unique on the page. kind is text, long-text, phone, choice or checkbox. options holds the answers of a choice question, from 2 to 12, and is empty for the other kinds. placeholder is optional example text shown in the empty field of a text, long-text or phone question, up to 160 characters. Defaults to none.

body['config']['confirmation']str

Text shown to the guest after booking and added to the confirmation email, up to 1,000 characters. Defaults to none.

body['config']['redirectUrl']str

An https:// page to send the guest to after booking, or an empty string for none, which is the default.

body['config']['appearance']['accent']str

The colour of buttons and the picked day, as #rrggbb. Defaults to #18181b.

body['config']['appearance']['theme']BookingTheme

auto follows the device of the guest, and light or dark forces one. Defaults to auto.

body['config']['appearance']['showAvatar']bool

Whether the page shows the photo of the person, or their initials when they have none. Defaults to True.

body['config']['appearance']['background']str

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, or a colour as #rrggbb. Defaults to default. image shows the photo of upload_background, so a new page cannot start with it.

body['config']['appearance']['fonts']['primary']BrandFontId | None

The font of the text: one of the ids in BRAND_FONT_IDS, such as inter or georgia, or None for the default. Defaults to None.

body['config']['appearance']['fonts']['secondary']BrandFontId | None

The font of the title, such as instrument-serif, or None to keep the title in the font of the text. Defaults to None.

body['config']['guestChanges']['cancel']bool

Whether a guest may cancel from the link in their emails. Defaults to True.

body['config']['guestChanges']['reschedule']bool

Whether a guest may move the meeting from the link in their emails. Defaults to True.

body['config']['guestChanges']['cutoffMinutes']int

How many minutes before the meeting those changes close, from 0 to 20,160. Defaults to 0.

body['config']['busy']['addresses']list[str] | None

The addresses whose invitations block time unless declined, at most 50. None, the default, checks every address the person holds.

body['config']['busy']['subscriptions']bool

Whether events from calendars the person subscribed to block time. Defaults to True.

body['config']['busy']['outOfOffice']bool

Whether the page offers no times while fromEmail is out of office. Defaults to True.

body['config']['seo']['title']str

The title of the browser tab and of a search result, up to 120 characters. Empty, the default, uses the name of the page and the host.

body['config']['seo']['description']str

The summary under the title in a search result, up to 300 characters. Empty, the default, uses the start of the description.

body['config']['seo']['indexable']bool

Whether search engines may list the page. Defaults to False, which asks them not to.

body['config']['extraGuests']int

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.

body['config']['reminders']['guest']list[int]

When the guest gets a reminder email, in minutes before the meeting: up to three of 10, 30, 60, 120, 1440, 2880 and 10080. Defaults to one day before, and an empty list sends none.

body['config']['reminders']['host']list[int]

The reminders each booked meeting carries on your own calendar, in minutes before it: up to three of 0, 5, 10, 15, 30, 60 and 1440. Defaults to 10.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingPageResource with the new id, status active, the slug and url of its link, and config with every default filled in.

Example

from nextmail import nextmail page = nextmail.bookings.create_page(    {        'name': 'Intro call',        'timezone': 'Europe/Berlin',        'config': {            'description': 'A first conversation about your project.',            'durations': [30, 60],            'location': {'kind': 'video', 'value': 'https://meet.example.com/ada'},            'rules': {'bufferAfterMinutes': 15},            'approval': True,        },    }) print(page['id'], page['url'], page['config']['fromEmail'])

Notes

  • A booking page belongs to one person. An API key acts as the workspace owner and makes a page of the owner, and a connected app makes a page of the person who connected it.

  • A person holds at most 25 pages. One more is a 403 booking_page_limit_reached.

  • A slug another page already uses is a 409 booking_link_taken. A slug that is not a valid link, a fromEmail the person may not send from, a video location without a link, an in-person one without an address and two questions with the same id are 422 invalid_booking_page, with the reason in the message. A few slugs such as manage and admin are reserved.

  • A value of the wrong type or length, a range that ends before it starts and a time zone in config.availability that is not known are 422 invalid_parameter with param naming the field. A key beside name, slug, timezone and config is 422 unknown_parameter.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • Not retried automatically. A slug made from the name gets a few random characters when the plain one is taken, so a retry after a lost response can leave two pages. List them and delete the spare.

Also available in

API
POST /booking-pages
TypeScript
nextmail.bookings.createPage()
Ruby
bookings.create_page
PHP
bookings->createPage
Go
Bookings.CreatePage
Java
bookings().createPage
C#
Bookings.CreatePageAsync
CLI
nextmail bookings create-page

bookings.update_page()

Change the name, the link, the status or any setting of a booking page

Scopescalendar:writeemails:send
Signature
def update_page(    id: str,    patch: BookingPagePatch,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingPageResource

Changes a booking page and returns it as it is stored. Send only what changes: a field left out stays as it is, and a patch with nothing in it is a 422.

config is merged, not replaced. A top-level value such as approval or fromEmail replaces the stored one. Inside location, availability, rules, appearance, guestChanges, busy and seo each field is merged on its own, so {'rules': {'dailyLimit': 4}} leaves the notice and the buffers alone. A list is replaced whole: send every entry of durations, questions, availability.weekly or availability.overrides again, not only the ones that change.

Set status to paused to stop offering times without losing the link, and to active to offer them again. Bookings already made keep their time whatever changes. A new slug moves the page to a new link and the old one stops working, so links already handed out break.

Parameters

idstrRequired

Booking page id such as bkp_5c1e9a7b3d2f48e6a0b4c7d1, as list_pages returns it.

patch['name']str

New name, shown to guests as the heading of the page. Trimmed, 1 to 80 characters. Left out, the name stays.

patch['slug']str

New last part of the public link: 3 to 60 lowercase letters and digits, with single hyphens between words. It is unique across Nextmail. Left out, the link stays.

patch['status']BookingPageStatus

active takes bookings. paused keeps the link working but offers no times. Left out, it stays.

patch['config']['description']str

Text shown under the name of the page, up to 2,000 characters. Basic Markdown works: bold, italic, links and lists. An empty string clears it.

patch['config']['hostName']str

The name guests see as the person they meet, up to 80 characters.

patch['config']['durations']list[int]

The meeting lengths a guest can pick, in minutes, replacing the list the page had: 1 to 4 of them, each a multiple of 5 between 5 and 720.

patch['config']['location']['kind']BookingLocationKind

Where the meeting happens: video with a fixed link in value, phone, where the guest is asked for a number, in-person with the address in value, or none.

patch['config']['location']['value']str

The https:// link of a video meeting or the address of an in-person one, up to 500 characters. It is dropped for phone and none.

patch['config']['availability']['timezone']str

The IANA time zone the hours of the page are read in, such as Europe/Berlin.

patch['config']['availability']['weekly']list[list[BookingTimeRange]]

All seven lists again, Sunday first, of the hours open on that weekday. Each range is a dict with start and end in minutes after midnight, so {'start': 540, 'end': 1020} is 09:00 to 17:00. An empty list closes the day, and a day takes at most 6 ranges.

patch['config']['availability']['overrides']list[BookingDateOverride]

Every date with its own hours again, at most 180, each a dict with date and ranges. date is YYYY-MM-DD in the time zone of the page, and an empty ranges closes that date. An empty list removes them all.

patch['config']['rules']['noticeMinutes']int

How many minutes ahead a booking has to be made, from 0 to 43,200.

patch['config']['rules']['horizonDays']int

How many days ahead the page offers times, from 1 to 365.

patch['config']['rules']['intervalMinutes']int | None

Minutes between two start times: 5, 10, 15, 20, 30, 45, 60, 90 or 120. None steps by the length of the meeting.

patch['config']['rules']['bufferBeforeMinutes']int

Minutes kept free before every meeting, from 0 to 240.

patch['config']['rules']['bufferAfterMinutes']int

Minutes kept free after every meeting, from 0 to 240.

patch['config']['rules']['dailyLimit']int | None

The most bookings the page takes on one day, from 1 to 50. None sets no limit.

patch['config']['approval']bool

True holds each new booking as a request until approve or decline answers it. False confirms it at once. Requests already waiting keep waiting.

patch['config']['fromEmail']str

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.

patch['config']['notifyHost']bool

Whether fromEmail gets an email about each new, moved or cancelled booking.

patch['config']['questions']list[BookingQuestion]

Every question again, at most 10, each a dict with id, kind, label, required, options and placeholder. id is a stable key for the answers: 4 to 16 lowercase letters and digits, unique on the page. kind is text, long-text, phone, choice or checkbox. options holds the answers of a choice question, from 2 to 12, and is empty for the other kinds. placeholder is optional example text shown in the empty field of a text, long-text or phone question, up to 160 characters. An empty list asks nothing more.

patch['config']['confirmation']str

Text shown to the guest after booking and added to the confirmation email, up to 1,000 characters. An empty string clears it.

patch['config']['redirectUrl']str

An https:// page to send the guest to after booking, or an empty string for none.

patch['config']['appearance']['accent']str

The colour of buttons and the picked day, as #rrggbb.

patch['config']['appearance']['theme']BookingTheme

auto follows the device of the guest, and light or dark forces one.

patch['config']['appearance']['showAvatar']bool

Whether the page shows the photo of the person, or their initials when they have none.

patch['config']['appearance']['background']str

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, a colour as #rrggbb, or image for the photo uploaded with upload_background. image without an uploaded photo is a 422 invalid_booking_page.

patch['config']['appearance']['fonts']['primary']BrandFontId | None

The font of the text: one of the ids in BRAND_FONT_IDS, such as inter or georgia, or None for the default. Left out, it keeps its value.

patch['config']['appearance']['fonts']['secondary']BrandFontId | None

The font of the title, such as instrument-serif, or None to keep the title in the font of the text. Left out, it keeps its value.

patch['config']['guestChanges']['cancel']bool

Whether a guest may cancel from the link in their emails.

patch['config']['guestChanges']['reschedule']bool

Whether a guest may move the meeting from the link in their emails.

patch['config']['guestChanges']['cutoffMinutes']int

How many minutes before the meeting those changes close, from 0 to 20,160.

patch['config']['busy']['addresses']list[str] | None

The addresses whose invitations block time unless declined, at most 50. None checks every address the person holds.

patch['config']['busy']['subscriptions']bool

Whether events from calendars the person subscribed to block time.

patch['config']['busy']['outOfOffice']bool

Whether the page offers no times while fromEmail is out of office.

patch['config']['seo']['title']str

The title of the browser tab and of a search result, up to 120 characters. An empty string goes back to the name of the page and the host.

patch['config']['seo']['description']str

The summary under the title in a search result, up to 300 characters. An empty string goes back to the start of the description.

patch['config']['seo']['indexable']bool

Whether search engines may list the page.

patch['config']['extraGuests']int

How many other people a guest may add to a booking, 0 to 10. Each one gets the invitation and every later change. 0 hides the field.

patch['config']['reminders']['guest']list[int]

When the guest gets a reminder email, in minutes before the meeting: up to three of 10, 30, 60, 120, 1440, 2880 and 10080. An empty list sends none.

patch['config']['reminders']['host']list[int]

The reminders each new booking carries on your own calendar, in minutes before it: up to three of 0, 5, 10, 15, 30, 60 and 1440.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingPageResource with the unchanged id, and everything else as it is now.

Example

from nextmail import nextmail page = nextmail.bookings.update_page(    'bkp_5c1e9a7b3d2f48e6a0b4c7d1',    {'config': {'durations': [45], 'rules': {'bufferAfterMinutes': 15, 'dailyLimit': 4}}},) print(page['config']['durations'], page['config']['rules'])

Notes

  • A missing page is a 404 booking_page_not_found, and so is a page that belongs to somebody else in the workspace.

  • A slug another page already uses is a 409 booking_link_taken. A slug that is not a valid link, a fromEmail the person may not send from, a video location without a link, an in-person one without an address and two questions with the same id are 422 invalid_booking_page, with the reason in the message.

  • An empty patch, a value of the wrong type or length, a range that ends before it starts and a time zone that is not known are 422 invalid_parameter. A key beside name, slug, status and config is 422 unknown_parameter.

  • 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.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • The SDK retries this call after a network failure, since the same patch sent twice leaves the same page.

Also available in

API
PATCH /booking-pages/{id}
TypeScript
nextmail.bookings.updatePage()
Ruby
bookings.update_page
PHP
bookings->updatePage
Go
Bookings.UpdatePage
Java
bookings().updatePage
C#
Bookings.UpdatePageAsync
CLI
nextmail bookings update-page

bookings.upload_background()

Upload the background photo of a booking page

Scopescalendar:writeemails:send
Signature
def upload_background(    id: str,    data: RawBody,    *,    content_type: BrandImageType | None = None,    api_key: str | None = None,    timeout: float | None = None,) -> BookingPageResource

Sends the image bytes as the request body, replacing the photo there was, and returns the page. The photo fills the public page behind the card: config.appearance.background becomes image and config.appearance.backgroundImage holds the address of the stored photo.

Up to 5 MB goes in, and it is fitted into 2560 by 1600 pixels and stored as WebP. It takes PNG, JPEG, WebP or GIF, and an animated image keeps its first frame. The server reads the type from content_type= alone. Bytes carry no type of their own, so without it they are sent as application/octet-stream and refused with 422 invalid_image: pass it on every call.

To go back to a preset or a colour and keep the photo for later, set config.appearance.background with update_page. remove_background deletes the photo.

Parameters

idstrRequired

Booking page id such as bkp_5c1e9a7b3d2f48e6a0b4c7d1, as list_pages returns it.

dataRawBodyRequired

The image as bytes, a bytearray or a memoryview, such as Path('photo.jpg').read_bytes().

content_typeBrandImageType

image/png, image/jpeg, image/webp or image/gif. Optional in the signature, but the server refuses an upload without it.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingPageResource showing the new photo in config.appearance.backgroundImage.

Example

from pathlib import Path from nextmail import nextmail page = nextmail.bookings.upload_background(    'bkp_5c1e9a7b3d2f48e6a0b4c7d1', Path('photo.jpg').read_bytes(), content_type='image/jpeg') appearance = page['config']['appearance']print(appearance['background'], appearance['backgroundImage'])

Notes

  • An SVG, an image over 5 MB or one that cannot be read is refused with 422 invalid_image.

  • A missing page is a 404 booking_page_not_found, and so is a page that belongs to somebody else in the workspace.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • A busy image service answers 503 image_busy and a failed save 502 image_not_stored, which the SDK retries like any other retryable status, since the same image sent twice leaves the same page.

Also available in

API
PUT /booking-pages/{id}/background
TypeScript
nextmail.bookings.uploadBackground()
Ruby
bookings.upload_background
PHP
bookings->uploadBackground
Go
Bookings.UploadBackground
Java
bookings().uploadBackground
C#
Bookings.UploadBackgroundAsync
CLI
nextmail bookings upload-background

bookings.remove_background()

Remove the background photo of a booking page

Scopescalendar:writeemails:send
Signature
def remove_background(    id: str,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingPageResource

Deletes the stored background photo of a booking page and returns the page. A page that showed the photo goes back to the default background, and one that showed a preset or a colour keeps it. Removing a photo that is not set changes nothing.

Parameters

idstrRequired

Booking page id such as bkp_5c1e9a7b3d2f48e6a0b4c7d1, as list_pages returns it.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingPageResource with config.appearance.backgroundImage set to None.

Example

from nextmail import nextmail page = nextmail.bookings.remove_background('bkp_5c1e9a7b3d2f48e6a0b4c7d1') appearance = page['config']['appearance']print(appearance['background'], appearance['backgroundImage'])

Notes

  • A missing page is a 404 booking_page_not_found, and so is a page that belongs to somebody else in the workspace.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • Retried automatically on network failure and retryable statuses, since a second attempt after one that went through finds nothing to remove.

Also available in

API
DELETE /booking-pages/{id}/background
TypeScript
nextmail.bookings.removeBackground()
Ruby
bookings.remove_background
PHP
bookings->removeBackground
Go
Bookings.RemoveBackground
Java
bookings().removeBackground
C#
Bookings.RemoveBackgroundAsync
CLI
nextmail bookings remove-background

bookings.delete_page()

Delete a booking page

Scopescalendar:write
Signature
def delete_page(    id: str,    *,    api_key: str | None = None,    timeout: float | None = None,) -> DeletedBookingPageResource

Deletes a booking page for good. Its public link stops working and the list of its bookings goes with it, so list no longer shows them and guests can no longer move or cancel through the links in their emails. The meetings already booked stay on the calendar, where calendar.cancel_event can still call one off.

There is no undo. To stop offering times and keep the page, its link and its bookings, use update_page with status paused.

Parameters

idstrRequired

Booking page id such as bkp_5c1e9a7b3d2f48e6a0b4c7d1, as list_pages returns it.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

DeletedBookingPageResource, a dict with object set to booking_page, the id and deleted set to True.

Example

from nextmail import nextmail removed = nextmail.bookings.delete_page('bkp_5c1e9a7b3d2f48e6a0b4c7d1') print(removed['id'], removed['deleted'])

Notes

  • It sends no email, so it needs calendar:write alone. Guests are not told that the page is gone.

  • The SDK does not retry a delete. A 404 booking_page_not_found on your own second attempt after a lost response means the first one worked.

  • 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.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

Also available in

API
DELETE /booking-pages/{id}
TypeScript
nextmail.bookings.deletePage()
Ruby
bookings.delete_page
PHP
bookings->deletePage
Go
Bookings.DeletePage
Java
bookings().deletePage
C#
Bookings.DeletePageAsync
CLI
nextmail bookings delete-page

bookings.list_times()

List the times a booking page offers

Scopescalendar:read
Signature
def list_times(    id: str,    *,    from_: datetime | str | None = None,    to: datetime | str | None = None,    duration_minutes: int | None = None,    booking_id: str | None = None,    api_key: str | None = None,    timeout: float | None = None,) -> BookingTimesResource

Returns the start times a guest could book on a page inside a window, in order. They are the 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, its daily limit, its notice and the out of office periods that close it.

The window starts at from_=, or now, and ends at to=, or 14 days later. It covers at most 62 days, and a later to= is cut back to that. duration_minutes= picks which meeting length the times are for and has to be one of the durations of the page. Left out, the shortest is used. Both bounds take a datetime or an ISO 8601 string. The SDK sends a datetime as a UTC instant, and reads a naive one as local time.

With booking_id= the times are the ones that booking can move to with reschedule: its own time counts as free, and they are for its length.

A paused page still answers, so the times can be checked before it is turned on. A page with a problem offers nothing.

Parameters

idstrRequired

Booking page id such as bkp_5c1e9a7b3d2f48e6a0b4c7d1, as list_pages returns it.

from_datetime | str

The start of the window, a datetime or an ISO 8601 string, sent as the from query parameter. Defaults to now.

todatetime | str

The end of the window, later than from_=. Defaults to 14 days after from_=, and counts for at most 62 days after it.

duration_minutesint

The meeting length in minutes, one of the durations of the page. Defaults to the shortest.

booking_idstr

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 duration_minutes= is ignored.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingTimesResource with pageId, the timezone of the page, the durationMinutes the times are for, and times, every open start time in the window as an ISO 8601 instant in UTC.

Example

from datetime import datetime, timedelta, timezone from nextmail import nextmail start = datetime.now(timezone.utc)offered = nextmail.bookings.list_times(    'bkp_5c1e9a7b3d2f48e6a0b4c7d1',    from_=start,    to=start + timedelta(days=7),    duration_minutes=30,) for opening in offered['times']:    print(opening)

Notes

  • A to= that is not later than from_= and a duration_minutes= the page does not offer are 422 invalid_parameter. A missing page is a 404 booking_page_not_found, and a booking_id= that is not a booking of this page a 404 booking_not_found.

  • The times are instants, so show them to a person in a time zone: timezone names the one the hours of the page are read in.

  • It reads the calendar as it is now and holds nothing. A time it lists can be gone a moment later, when a guest books it.

  • 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.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

Also available in

API
GET /booking-pages/{id}/times
TypeScript
nextmail.bookings.listTimes()
Ruby
bookings.list_times
PHP
bookings->listTimes
Go
Bookings.ListTimes
Java
bookings().listTimes
C#
Bookings.ListTimesAsync
CLI
nextmail bookings list-times

bookings.list()

List the meetings guests booked, a page at a time

Scopescalendar:readPages through results
Signature
def list(    *,    limit: int | None = None,    cursor: str | None = None,    view: BookingView | None = None,    page_id: str | None = None,    page_ids: Sequence[str] | None = None,    q: str | None = None,    from_: datetime | str | None = None,    to: datetime | str | None = None,    api_key: str | None = None,    timeout: float | None = None,) -> Page[BookingResource]

Returns one page of bookings: the meetings guests booked on the booking pages of the person, or on some of them with page_ids=. q= searches the guest and the page, and from_= and to= keep the meetings that start in a window. list_all collects every page and iterate walks them lazily. A booking is a calendar event with the guest invited, so it shows wherever the calendar does, and a meeting moved or cancelled in the calendar reads as moved or cancelled here.

view= picks which bookings are listed. upcoming, the default, holds the confirmed meetings that are not over. pending holds the requests that wait for approve or decline, on a page whose config.approval is True. past holds the meetings that are over and the requests nobody answered in time, and ended holds the ones that were declined or cancelled. upcoming and pending come soonest first, past and ended latest first.

Each booking names its page in pageId and pageName, the guest in guest, what they answered in answers and its calendar event in eventId.

Parameters

limitint

Page size, from 1 to 100. The server defaults to 30.

cursorstr

The nextCursor of the previous page, passed back as it came. Leave it out for the first page.

viewBookingView

Which bookings to list: upcoming, pending, past or ended. Defaults to upcoming.

page_idstr

Only the bookings of this booking page, by its id. Left out, the bookings of every page of the person are listed.

page_idsSequence[str]

Only the bookings of these booking pages, at most 25 ids, sent comma separated. Left out or empty, every page of the person.

qstr

Only the bookings whose guest name, guest email or page name contains this text, at most 200 characters. Case and accents are ignored.

from_datetime | str

Only the meetings that start at or after this instant, as a datetime or an ISO 8601 string, sent as the from query parameter.

todatetime | str

Only the meetings that start before this instant, later than from_=.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

Page[BookingResource], a dict with items, hasMore and nextCursor. Each item has id, pageId, pageName, status, expired, past, start, end, durationMinutes, guest, answers, location, eventId, endedBy, endReason, rescheduleCount, guestMailFailed and createdAt.

Example

from nextmail import nextmail page = nextmail.bookings.list(view='pending') for booking in page['items']:    print(booking['id'], booking['pageName'], booking['guest']['name'], booking['start'])

Notes

  • status is pending while a booking 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 is True for a request nobody answered before its time came, and past once the meeting is over.

  • A page_id= or one of page_ids= that is not a page of the person answers 404 booking_page_not_found, more than 25 page_ids= or a to= that is not later than from_= 422 invalid_parameter, and a cursor this list did not hand out 400 invalid_cursor.

  • A search with q= reads up to 1000 of the newest matching bookings of the view, so narrow an old view with from_= and to= to search all of it.

  • The cursor marks how far into the view the last page reached. A booking that enters or leaves the view between two pages shifts the rows after it, so read the view again when an exact list matters.

  • An API key acts as the workspace owner and reads the bookings of the owner, and a connected app reads the bookings of the person who connected it. One guest address holds at most 3 upcoming bookings on a page.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

Also available in

API
GET /bookings
TypeScript
nextmail.bookings.list()
Ruby
bookings.list
PHP
bookings->list
Go
Bookings.List
Java
bookings().list
C#
Bookings.ListAsync
CLI
nextmail bookings list

bookings.list_all()

Collect every booking of a view into one list

Scopescalendar:readPages through results
Signature
def list_all(    *,    limit: int | None = None,    cursor: str | None = None,    view: BookingView | None = None,    page_id: str | None = None,    page_ids: Sequence[str] | None = None,    q: str | None = None,    from_: datetime | str | None = None,    to: datetime | str | None = None,    api_key: str | None = None,    timeout: float | None = None,) -> builtins.list[BookingResource]

Walks every page of list and returns all bookings of one view, in the order of that view: upcoming and pending soonest first, past and ended latest first. One request per page. Give page_ids=, q=, from_= or to= to collect only the bookings that match.

Parameters

limitint

Page size for each request, from 1 to 100. The server defaults to 30.

cursorstr

Starts the walk after this cursor instead of the first page.

viewBookingView

Which bookings to collect: upcoming, pending, past or ended. Defaults to upcoming.

page_idstr

Only the bookings of this booking page, by its id. Left out, the bookings of every page of the person are collected.

page_idsSequence[str]

Only the bookings of these booking pages, at most 25 ids, sent comma separated. Left out or empty, every page of the person.

qstr

Only the bookings whose guest name, guest email or page name contains this text, at most 200 characters. Case and accents are ignored.

from_datetime | str

Only the meetings that start at or after this instant, as a datetime or an ISO 8601 string, sent as the from query parameter.

todatetime | str

Only the meetings that start before this instant, later than from_=.

api_keystr

Overrides the client API key for every page of this walk.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

list[BookingResource] holding every booking of the view.

Example

from nextmail import nextmail bookings = nextmail.bookings.list_all(view='upcoming', limit=100) unsent = [booking for booking in bookings if booking['guestMailFailed']] for booking in unsent:    print(booking['id'], booking['guest']['email'], booking['start'])

Notes

  • If any page fails, the call raises and the bookings already fetched are discarded.

  • The past and ended views grow without end, so prefer iterate there and stop when you have read far enough back.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

Also available in

API
GET /bookings
TypeScript
nextmail.bookings.listAll()
Ruby
bookings.list_all
PHP
bookings->listAll
Go
Bookings.ListAll
Java
bookings().listAll
C#
Bookings.ListAllAsync

bookings.iterate()

Stream the bookings of a view one at a time

Scopescalendar:readPages through results
Signature
def iterate(    *,    limit: int | None = None,    cursor: str | None = None,    view: BookingView | None = None,    page_id: str | None = None,    page_ids: Sequence[str] | None = None,    q: str | None = None,    from_: datetime | str | None = None,    to: datetime | str | None = None,    api_key: str | None = None,    timeout: float | None = None,) -> Iterator[BookingResource]

Returns a generator that yields the bookings of one view individually, in the order of that view, and requests the next page only once the current one is drained. Nothing is fetched until you consume it, and breaking out of the loop stops the requests.

Parameters

limitint

Page size for each request, from 1 to 100. The server defaults to 30.

cursorstr

Starts the walk after this cursor instead of the first page.

viewBookingView

Which bookings to walk: upcoming, pending, past or ended. Defaults to upcoming.

page_idstr

Only the bookings of this booking page, by its id. Left out, the bookings of every page of the person are walked.

page_idsSequence[str]

Only the bookings of these booking pages, at most 25 ids, sent comma separated. Left out or empty, every page of the person.

qstr

Only the bookings whose guest name, guest email or page name contains this text, at most 200 characters. Case and accents are ignored.

from_datetime | str

Only the meetings that start at or after this instant, as a datetime or an ISO 8601 string, sent as the from query parameter.

todatetime | str

Only the meetings that start before this instant, later than from_=.

api_keystr

Overrides the client API key for every page of this walk.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

Iterator[BookingResource], a generator yielding one booking per step.

Example

from nextmail import nextmail for booking in nextmail.bookings.iterate(view='ended'):    print(booking['start'], booking['pageName'], booking['endedBy'], booking['endReason'])

Notes

  • The generator is lazy, so an abandoned loop costs only the pages you consumed.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

Also available in

API
GET /bookings
TypeScript
nextmail.bookings.iterate()
Ruby
bookings.iterate
PHP
bookings->iterate
Go
Bookings.Iterate
Java
bookings().iterate
C#
Bookings.IterateAsync

bookings.get()

Read one booking by id

Scopescalendar:read
Signature
def get(    id: str,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingResource

Looks up a single booking and returns it in the same shape as a row of list: the booking page it was made on, the guest with the time zone they booked in, what they answered to the questions of the page, where the meeting happens as the guest was told, the calendar event it is and how it ended if it did.

A booking follows its calendar event. Reading one first catches up with the calendar, so a meeting that was moved there shows its new start and end, and one that was cancelled or deleted there reads cancelled, or declined when it still waited for approval. endedBy says whether the host or the guest declined or cancelled it, and endReason holds the reason they gave. guestMailFailed is True when the last email to the guest could not be sent, and resend_email tries again.

Parameters

idstrRequired

Booking id such as bkg_2b8d4f6a1c3e5079b6d8f0a2, as list returns it.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingResource with id, pageId, pageName, status, expired, past, start, end, durationMinutes, guest, answers, location, eventId, endedBy, endReason, rescheduleCount, guestMailFailed and createdAt.

Example

from nextmail import nextmail booking = nextmail.bookings.get('bkg_2b8d4f6a1c3e5079b6d8f0a2') print(booking['status'], booking['start'], booking['guest']['name'], booking['guest']['email']) for answer in booking['answers']:    print(answer['label'], answer['value'])

Notes

  • A missing booking raises NextmailApiError with is_not_found set to True and code booking_not_found. A booking on a page that belongs to somebody else in the workspace is missing too.

  • eventId is the id calendar.get_event reads. It is None once the booking ended and its event was removed.

  • Each answer carries the id, label and kind of its question as it was asked, and its value as text. A checkbox answers yes or no.

  • An API key acts as the workspace owner and reads the bookings of the owner, and a connected app reads the bookings of the person who connected it.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

Also available in

API
GET /bookings/{id}
TypeScript
nextmail.bookings.get()
Ruby
bookings.get
PHP
bookings->get
Go
Bookings.Get
Java
bookings().get
C#
Bookings.GetAsync
CLI
nextmail bookings get

bookings.approve()

Confirm a booking that waits for approval

Scopescalendar:writeemails:send
Signature
def approve(    id: str,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingResource

Confirms a booking that waits for approval, on a booking page whose config.approval is True. The hold on the calendar becomes a confirmed meeting, and the guest is told by email, sent from the address of the page with the calendar invitation attached. It takes no body.

The email goes out as config.fromEmail, so the call needs emails:send beside calendar:write. list with view='pending' reads the bookings that wait.

Parameters

idstrRequired

Booking id such as bkg_2b8d4f6a1c3e5079b6d8f0a2, as list returns it.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingResource with status confirmed, and guestMailFailed saying whether the email to the guest went out.

Example

from nextmail import nextmail booking = nextmail.bookings.approve('bkg_2b8d4f6a1c3e5079b6d8f0a2') print(booking['status'], booking['start'], booking['guestMailFailed'])

Notes

  • A booking that is not waiting for approval answers 409 booking_not_pending, and one whose time has passed 409 booking_ended. A missing one is a 404 booking_not_found.

  • The booking is confirmed even when the email cannot be sent. guestMailFailed is then True, and resend_email sends it again.

  • An API key acts as the workspace owner and reaches the bookings of the owner, and a connected app reaches the bookings of the person who connected it.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • The SDK does not retry it, because a retry could email the guest twice. A 409 booking_not_pending on your own second attempt after a lost response means the first one worked or the guest withdrew, and get says which.

Also available in

API
POST /bookings/{id}/approve
TypeScript
nextmail.bookings.approve()
Ruby
bookings.approve
PHP
bookings->approve
Go
Bookings.Approve
Java
bookings().approve
C#
Bookings.ApproveAsync
CLI
nextmail bookings approve

bookings.decline()

Turn down a booking that waits for approval

Scopescalendar:writeemails:send
Signature
def decline(    id: str,    body: BookingReason | None = None,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingResource

Turns down a booking that waits for approval and frees its time, so the page offers that time again. The guest is told by email, sent from the address of the page, with reason in it when one is given. Call it with no body to decline without a reason.

The email goes out as config.fromEmail, so the call needs emails:send beside calendar:write.

Parameters

idstrRequired

Booking id such as bkg_2b8d4f6a1c3e5079b6d8f0a2, as list returns it.

body['reason']str | None

A sentence for the guest, trimmed, at most 500 characters, included in the email they get. Left out or None, the email gives no reason.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingResource with status declined, endedBy host and endReason holding the reason, or None.

Example

from nextmail import nextmail booking = nextmail.bookings.decline(    'bkg_2b8d4f6a1c3e5079b6d8f0a2',    {'reason': 'I am away that week. Please pick a time after the 20th.'},) print(booking['status'], booking['endReason'])

Notes

  • A booking that is not waiting for approval answers 409 booking_not_pending. To call off a confirmed meeting, use cancel. A missing booking is a 404 booking_not_found.

  • A reason over 500 characters is 422 invalid_parameter, and a key the body does not take is 422 unknown_parameter.

  • The booking is declined even when the email cannot be sent. guestMailFailed is then True, and resend_email sends it again.

  • An API key acts as the workspace owner and reaches the bookings of the owner, and a connected app reaches the bookings of the person who connected it.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • The SDK does not retry it, because a retry could email the guest twice. A 409 booking_not_pending on your own second attempt after a lost response means the first one worked or somebody else answered, and get says which.

Also available in

API
POST /bookings/{id}/decline
TypeScript
nextmail.bookings.decline()
Ruby
bookings.decline
PHP
bookings->decline
Go
Bookings.Decline
Java
bookings().decline
C#
Bookings.DeclineAsync
CLI
nextmail bookings decline

bookings.cancel()

Cancel a booked meeting

Scopescalendar:writeemails:send
Signature
def cancel(    id: str,    body: BookingReason | None = None,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingResource

Cancels a meeting that has not ended yet and cancels its calendar event. The guest is told by email, sent from the address of the page with the cancellation attached, and with reason in it when one is given. Call it with no body to cancel without a reason.

A booking that still waits for approval is declined instead, so it ends as declined, not cancelled. The email goes out as config.fromEmail, so the call needs emails:send beside calendar:write.

Parameters

idstrRequired

Booking id such as bkg_2b8d4f6a1c3e5079b6d8f0a2, as list returns it.

body['reason']str | None

A sentence for the guest, trimmed, at most 500 characters, included in the email they get. Left out or None, the email gives no reason.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingResource with status cancelled, or declined when it still waited for approval, endedBy host and endReason holding the reason, or None.

Example

from nextmail import nextmail booking = nextmail.bookings.cancel(    'bkg_2b8d4f6a1c3e5079b6d8f0a2',    {'reason': 'Something urgent came up. Please book another time.'},) print(booking['status'], booking['endedBy'], booking['endReason'])

Notes

  • A booking that was already declined or cancelled, or whose meeting is over, answers 409 booking_ended. A missing one is a 404 booking_not_found.

  • There is no undo. The time is free again and the guest has to book once more.

  • A reason over 500 characters is 422 invalid_parameter, and a key the body does not take is 422 unknown_parameter.

  • The booking is cancelled even when the email cannot be sent. guestMailFailed is then True, and resend_email sends it again.

  • An API key acts as the workspace owner and reaches the bookings of the owner, and a connected app reaches the bookings of the person who connected it.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • The SDK does not retry it, because a retry could email the guest twice. A 409 booking_ended on your own second attempt after a lost response means the first one worked or the guest cancelled, and get says which.

Also available in

API
POST /bookings/{id}/cancel
TypeScript
nextmail.bookings.cancel()
Ruby
bookings.cancel
PHP
bookings->cancel
Go
Bookings.Cancel
Java
bookings().cancel
C#
Bookings.CancelAsync
CLI
nextmail bookings cancel

bookings.resend_email()

Send the guest the email about their booking again

Scopescalendar:writeemails:send
Signature
def resend_email(    id: str,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingResource

Sends the guest the email that matches where the booking stands now: the request while it waits for approval, the confirmation with its invitation once it is confirmed, or the notice that it was declined or cancelled, with the reason that was given. Use it when guestMailFailed is True. It takes no body and changes nothing else about the booking.

Parameters

idstrRequired

Booking id such as bkg_2b8d4f6a1c3e5079b6d8f0a2, as list returns it.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingResource with guestMailFailed as it is after the send: False when the email went out, True when it failed again.

Example

from nextmail import nextmail booking = nextmail.bookings.resend_email('bkg_2b8d4f6a1c3e5079b6d8f0a2') if booking['guestMailFailed']:    print('Still not sent to', booking['guest']['email'])

Notes

  • A missing booking is a 404 booking_not_found.

  • It answers 200 whether or not the email went out, so read guestMailFailed to know.

  • An API key acts as the workspace owner and reaches the bookings of the owner, and a connected app reaches the bookings of the person who connected it.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • Not retried automatically: every call sends another email, so a retry after a lost response can reach the guest twice.

Also available in

API
POST /bookings/{id}/resend
TypeScript
nextmail.bookings.resendEmail()
Ruby
bookings.resend_email
PHP
bookings->resendEmail
Go
Bookings.ResendEmail
Java
bookings().resendEmail
C#
Bookings.ResendEmailAsync
CLI
nextmail bookings resend-email

bookings.analytics()

Read how the booking pages did over a window

Scopescalendar:read
Signature
def analytics(    *,    page_ids: Sequence[str] | None = None,    days: int | None = None,    minutes: int | None = None,    grain: TrackingGrain | None = None,    offset_minutes: int | None = None,    api_key: str | None = None,    timeout: float | None = None,) -> BookingAnalyticsResource

Returns the numbers behind the Analytics tab of Booking in one request: 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.

A booking counts in the window it was made in, whatever its meeting time. totals.booked is every booking made in the window, and confirmed, pending, expired, declined and cancelled split it by what became of each one, so they add up to booked. cancelledByGuest and cancelledByHost split cancelled, rescheduled counts the meetings moved at least once, and minutesBooked adds up the length of the confirmed meetings.

upcoming ignores the window: it counts the confirmed meetings that have not ended and the requests still waiting, and gives the start of the next meeting. series is sparse and oldest first, so a chart must fill the gaps. grain= sets the bucket width and the key shape, YYYY-MM-DD, YYYY-MM-DDTHH or YYYY-MM-DDTHH:MM, and offset_minutes= shifts the boundaries and the weekdays so days break where the reader's day does. page_ids= narrows everything to some pages, such as one page for its own Analytics tab.

Parameters

page_idsSequence[str]

Count only these booking pages, at most 25, such as ['bkp_5c1e9a7b3d2f48e6a0b4c7d1'], sent comma separated. Left out or empty, every page of the person.

daysint

How far back to look, from 1 to 1095, defaulting to 30.

minutesint

The window in minutes, from 1 to 1576800, which wins over days= when both are sent.

grainTrackingGrain

Bucket width: minute, hour or day, defaulting to day.

offset_minutesint

Minutes east of UTC to cut the buckets and the weekdays in, from -840 to 840, defaulting to 0. Pass time.localtime().tm_gmtoff // 60 for the local zone.

api_keystr

Overrides the client's API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingAnalyticsResource, a dict with object set to booking_analytics, pageId, pageIds, since, until, grain, offsetMinutes, totals, upcoming, series, pages and weekdays. totals has booked, confirmed, pending, expired, declined, cancelled, cancelledByGuest, cancelledByHost, rescheduled, minutesBooked and cancellationRate, upcoming has confirmed, waiting and nextStart, each entry of series has bucket, booked and cancelled, each entry of pages has pageId, name, booked and cancelled, and weekdays holds seven entries with weekday and meetings, from Sunday (0) to Saturday (6).

Example

import time from nextmail import nextmail analytics = nextmail.bookings.analytics(    days=90,    offset_minutes=time.localtime().tm_gmtoff // 60,) totals = analytics['totals']print(totals['booked'], totals['cancellationRate'], analytics['upcoming']['nextStart'])

Notes

  • totals.cancellationRate is cancelled divided by booked, a float of at most 1, and None when nothing was booked in the window.

  • pageIds echoes the pages counted and is empty for every page. pageId is that page when exactly one is counted, and None otherwise. A page that is not one of the person is a 404 booking_page_not_found.

  • pages lists at most 10 pages, the ones with the most bookings first. A key limited to particular addresses is refused with capability_unsupported, because a booking page reads the whole calendar.

  • Read only, so the SDK retries it after a network failure like any other read.

Also available in

API
GET /bookings/analytics
TypeScript
nextmail.bookings.analytics()
Ruby
bookings.analytics
PHP
bookings->analytics
Go
Bookings.Analytics
Java
bookings().analytics
C#
Bookings.AnalyticsAsync
CLI
nextmail bookings analytics

bookings.reschedule()

Move a booked meeting to a new time

Scopescalendar:writeemails:send
Signature
def reschedule(    id: str,    body: BookingReschedule,    *,    api_key: str | None = None,    timeout: float | None = None,) -> BookingResource

Moves a meeting that has not started to a new time and moves its calendar event with it. The meeting keeps its length, so only start is sent. The time has to be one the page offers for this booking: list_times with booking_id= lists them, counting the current time of the booking as free. The page may be paused, and the cut-off that limits guests does not apply to the host.

The guest is told by email, sent from the address of the page with the updated invitation attached and with reason in it when one is given, and so is everyone the guest added. The host gets a copy at the same address unless config.notifyHost is False. A booking that waited for approval is confirmed at the new time, because the host chose it. The email goes out as config.fromEmail, so the call needs emails:send beside calendar:write.

Parameters

idstrRequired

Booking id such as bkg_2b8d4f6a1c3e5079b6d8f0a2, as list returns it.

body['start']datetime | strRequired

The new start, as a datetime or an ISO 8601 string. The SDK sends a datetime as a UTC instant. It has to be one of the times list_times returns for the page with booking_id= set to this booking.

body['reason']str | None

A sentence for the guest, trimmed, at most 500 characters, included in the email about the new time. Left out or None, the email gives no reason.

api_keystr

Overrides the client API key for this call only.

timeoutfloat

Seconds this call may take, the response included, before it raises NextmailNetworkError with is_timeout. It overrides the client's timeout for this call, and 0 turns the limit off.

Returns

BookingResource at its new time: start and end moved, status confirmed and rescheduleCount one higher. guestMailFailed is True when the email to the guest could not be sent.

Example

from nextmail import nextmail booking = nextmail.bookings.get('bkg_2b8d4f6a1c3e5079b6d8f0a2')offered = nextmail.bookings.list_times(booking['pageId'], booking_id=booking['id']) moved = nextmail.bookings.reschedule(    booking['id'],    {        'start': offered['times'][0],        'reason': 'Something came up, so I moved us to the next free time.',    },) print(moved['start'], moved['rescheduleCount'])

Notes

  • A time the page does not offer for this booking answers 409 booking_time_unavailable: it is taken, outside the hours, inside the notice or past how far ahead the page books. Read list_times again and pick another.

  • A booking that was declined or cancelled, or whose meeting has started, answers 409 booking_ended. A missing one is a 404 booking_not_found.

  • Sending the time the meeting already has changes nothing and sends no email.

  • The booking moves even when the email cannot be sent. guestMailFailed is then True, and resend_email sends it again.

  • An API key acts as the workspace owner and reaches the bookings of the owner, and a connected app reaches the bookings of the person who connected it.

  • A key or an app limited to particular addresses or domains is refused with 422 capability_unsupported, because a booking page reads the whole calendar of its person.

  • The SDK does not retry it, because a retry could email the guest twice. Read the booking with get after a lost response to see where it landed.

Also available in

API
POST /bookings/{id}/reschedule
TypeScript
nextmail.bookings.reschedule()
Ruby
bookings.reschedule
PHP
bookings->reschedule
Go
Bookings.Reschedule
Java
bookings().reschedule
C#
Bookings.RescheduleAsync
CLI
nextmail bookings reschedule