# API reference The REST API lives at `https://daybooked.io/api/v1`: send `Authorization: Bearer daybooked_live_…` and JSON. Lists come back as `{ data }` and errors as `{ "error": { "code", "message" } }` with an HTTP status. Every operation is also an MCP tool of the same name, and this page is generated from the schemas behind the OpenAPI document. URL: https://daybooked.io/docs/api Base URL: https://daybooked.io/api/v1 · OpenAPI: https://daybooked.io/api/v1/openapi.json · MCP: https://daybooked.io/api/mcp Auth: `Authorization: Bearer daybooked_live_…` ## Offerings ### offerings_list: GET /offerings List offerings (classes, appointments and rentals), paused ones included Request: - kind (query, class | appointment | rental): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - data[].name (string, required) - data[].description (string, required) - data[].location (string, required): Where it meets, as guests read it: an address, a place or GPS coordinates. Or an https meeting link for an offering online, which guests join - data[].duration_minutes (integer, required): Length of a class session or appointment, or of one rental period (1440 = a day) - data[].capacity (integer, required): class: seats per session · appointment: parallel bookings per slot · rental: items in stock - data[].max_per_booking (integer, required): Most seats, people or items in one booking. An appointment is one-on-one at 1 (its default); more lets a guest book for a party - data[].price_cents (integer, required): class: per seat · appointment: per appointment, for its first person (see guest_price_cents) · rental: per item per period - data[].guest_price_cents (integer | null): appointment: what each additional guest in a party adds; null (the default) charges each the full price, 0 makes them free - data[].deposit_cents (integer | null): A deposit guests pay at booking where they pay online, in the currency's minor units (at most the total); the rest is due at the start. Null: the whole total - data[].deposit_percent (integer | null): A deposit as a percent of the total, 1 to 99, paid at booking where guests pay online; null: the whole total - data[].slot_interval_minutes (integer | null, required): Minutes between start times; null means back to back - data[].buffer_minutes (integer, required) - data[].min_notice_minutes (integer, required) - data[].max_advance_days (integer, required) - data[].max_periods (integer, required): Rentals: the most periods one booking can span - data[].active (boolean, required): false pauses booking: guests and agents can't book it, and it stays in your dashboard - data[].metadata (any, required): Free-form JSON object for your own integrations - data[].lat (number | null): The meeting point's latitude, for its map link and the weather call - data[].lon (number | null) - data[].place_id (string | null): Google Maps' place ID for the location, which the guest's map link opens - data[].gauge_site (string | null): A USGS river gauge's site number - data[].schedule (hours | calendar | null): An appointment's: weekly hours or calendar entries; null for other kinds - data[].waiver_required (boolean): Each person booked signs your waiver (waiver.get) on their phone before they come - data[].waitlist_enabled (boolean): A full time keeps a waitlist that guests join, emailed when a place opens (waitlist_list). Switched off, everyone waiting comes off and is emailed - data[].course (boolean): A class sold as a course: availability.get lists each calendar entry that ends as one slot, and bookings.create takes its series_id to book every time of it - data[].questions (object[]): What guests answer as they book, in this order: ask the guest, then pass the answers to bookings.create as answers, keyed by each question's id - data[].questions[].id (string, required): bookings.create takes the answer to this question under this id - data[].questions[].label (string, required): The question as guests read it - data[].questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - data[].questions[].options (string[]): A choice's options: its answer is one of them, as listed - data[].questions[].required (boolean, required): Guests must answer it to book online - data[].photo_url (string | null): Its photo, at the top of its card on the booking page: a JPEG's absolute URL, or null without one. Read-only: photos are uploaded in the dashboard (the offering's Photo) - data[].created_at (string, required): ISO 8601 timestamp (UTC) ### offerings_create: POST /offerings Create an offering. Only kind and name are required; everything else has defaults per kind. Appointments and rentals open daily 9:00–17:00 (org time) until you set hours; classes need sessions. Request: - name (body, string · ≤ 120 chars, required) - description (body, string · ≤ 2000 chars) - location (body, string · ≤ 500 chars): Where it meets, as guests read it, with a Google Maps link: an address, a place with its town, or GPS coordinates ("45.6770, -111.0429"). Or an https meeting link (Zoom, Meet, Teams) for an offering online: guests get Join instead of a map, and its times on their own clock - duration_minutes (body, integer · 5–43200): Length of a class session or appointment, or of one rental period (1440 = a day) - capacity (body, integer · 1–10000): class: seats per session · appointment: parallel bookings per slot · rental: items in stock - max_per_booking (body, integer · 1–10000): Most seats, people or items in one booking. An appointment is one-on-one at 1 (its default); more lets a guest book for a party - price_cents (body, integer · ≥ 0): class: per seat · appointment: per appointment, for its first person (see guest_price_cents) · rental: per item per period - guest_price_cents (body, integer | null): appointment: what each additional guest in a party adds; null (the default) charges each the full price, 0 makes them free - deposit_cents (body, integer | null): A deposit to hold a place, in the currency's minor units: where guests pay online at booking, they pay this much (at most the total) and the rest at the start. Null (the default) takes the whole total. One or the other with deposit_percent: setting one clears the other, both at once is 400 deposit_conflict - deposit_percent (body, integer | null): A deposit as a percent of the total, 1 to 99, rounded half up to a whole minor unit (after any promo code). Null (the default) takes the whole total - slot_interval_minutes (body, integer | null): Minutes between start times; null means back to back - buffer_minutes (body, integer · 0–1440): Gap between bookings: minutes kept free before and after each one, for rentals and appointments on weekly hours (a calendar's times keep none) - min_notice_minutes (body, integer · 0–43200): When booking closes: how many minutes before a time starts (0: open until it starts) - max_advance_days (body, integer · 1–730) - max_periods (body, integer · 1–60): Rentals: the most periods one booking can span - active (body, boolean): false pauses booking: guests and agents can't book it, and it stays in your dashboard - metadata (body, object): Free-form JSON for your own integrations - lat (body, number | null): The meeting point's latitude, for its map link and the weather call. A new location without lat and lon sets them from coordinates typed in it, or clears them - lon (body, number | null): The meeting point's longitude - place_id (body, string | null): Google Maps' place ID for the location, which the guest's map link opens; the dashboard's Location search sets it, and a new location without it clears it - gauge_site (body, string | null): A USGS river gauge's site number (e.g. 13022500), for the river's flow - schedule (body, hours | calendar): Appointments only: open on weekly hours (offerings.set_hours) or on calendar entries (series.create), one or the other; new ones use the calendar, and it moves to hours only once its calendar has no times to come - waiver_required (body, boolean): Each person booked signs your waiver on their phone before they come: one per seat or guest, one per rental booking. Needs your waiver's text first (waiver.update; 409 waiver_missing) - waitlist_enabled (body, boolean): A full time keeps a waitlist: guests whose party doesn't fit join it from the booking page, and when a place opens everyone whose party fits is emailed at once (waitlist_list). Times on a calendar only: a class's, or an appointment's on its calendar (400 waitlist_not_supported) - questions (body, object[] · ≤ 6 items): What guests answer as they book, up to 6, in this order; the whole list replaces the last. bookings.create takes their answers keyed by each question's id - questions[].id (body, string): Keep a question's id to keep the answers given to it; a new question gets one - questions[].label (body, string · ≤ 80 chars, required): The question as guests read it, e.g. Shoe size - questions[].type (body, text | yes_no | choice, required): text: a line in their words · yes_no: yes or no · choice: one of its options - questions[].options (body, string[] · ≤ 8 items): A choice's options, 2 to 8, each once; the other types take none - questions[].required (body, boolean): Guests must answer it to book (false by default) - course (body, boolean): Classes only (409 not_a_class): sell it as a course. One booking (bookings.create's series_id) takes a seat in every time of a calendar entry from its first to come, at price_cents per seat for the whole course; a repeating entry needs ends_on. No waitlist (409 waitlist_conflict) - kind (body, class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods Response 201: JSON - id (string, required) - org_id (string, required) - kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - name (string, required) - description (string, required) - location (string, required): Where it meets, as guests read it: an address, a place or GPS coordinates. Or an https meeting link for an offering online, which guests join - duration_minutes (integer, required): Length of a class session or appointment, or of one rental period (1440 = a day) - capacity (integer, required): class: seats per session · appointment: parallel bookings per slot · rental: items in stock - max_per_booking (integer, required): Most seats, people or items in one booking. An appointment is one-on-one at 1 (its default); more lets a guest book for a party - price_cents (integer, required): class: per seat · appointment: per appointment, for its first person (see guest_price_cents) · rental: per item per period - guest_price_cents (integer | null): appointment: what each additional guest in a party adds; null (the default) charges each the full price, 0 makes them free - deposit_cents (integer | null): A deposit guests pay at booking where they pay online, in the currency's minor units (at most the total); the rest is due at the start. Null: the whole total - deposit_percent (integer | null): A deposit as a percent of the total, 1 to 99, paid at booking where guests pay online; null: the whole total - slot_interval_minutes (integer | null, required): Minutes between start times; null means back to back - buffer_minutes (integer, required) - min_notice_minutes (integer, required) - max_advance_days (integer, required) - max_periods (integer, required): Rentals: the most periods one booking can span - active (boolean, required): false pauses booking: guests and agents can't book it, and it stays in your dashboard - metadata (any, required): Free-form JSON object for your own integrations - lat (number | null): The meeting point's latitude, for its map link and the weather call - lon (number | null) - place_id (string | null): Google Maps' place ID for the location, which the guest's map link opens - gauge_site (string | null): A USGS river gauge's site number - schedule (hours | calendar | null): An appointment's: weekly hours or calendar entries; null for other kinds - waiver_required (boolean): Each person booked signs your waiver (waiver.get) on their phone before they come - waitlist_enabled (boolean): A full time keeps a waitlist that guests join, emailed when a place opens (waitlist_list). Switched off, everyone waiting comes off and is emailed - course (boolean): A class sold as a course: availability.get lists each calendar entry that ends as one slot, and bookings.create takes its series_id to book every time of it - questions (object[]): What guests answer as they book, in this order: ask the guest, then pass the answers to bookings.create as answers, keyed by each question's id - questions[].id (string, required): bookings.create takes the answer to this question under this id - questions[].label (string, required): The question as guests read it - questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - questions[].options (string[]): A choice's options: its answer is one of them, as listed - questions[].required (boolean, required): Guests must answer it to book online - photo_url (string | null): Its photo, at the top of its card on the booking page: a JPEG's absolute URL, or null without one. Read-only: photos are uploaded in the dashboard (the offering's Photo) - created_at (string, required): ISO 8601 timestamp (UTC) ### offerings_get: GET /offerings/{id} Get one offering, with the questions guests answer as they book: bookings.create takes their answers, keyed by question id Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - org_id (string, required) - kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - name (string, required) - description (string, required) - location (string, required): Where it meets, as guests read it: an address, a place or GPS coordinates. Or an https meeting link for an offering online, which guests join - duration_minutes (integer, required): Length of a class session or appointment, or of one rental period (1440 = a day) - capacity (integer, required): class: seats per session · appointment: parallel bookings per slot · rental: items in stock - max_per_booking (integer, required): Most seats, people or items in one booking. An appointment is one-on-one at 1 (its default); more lets a guest book for a party - price_cents (integer, required): class: per seat · appointment: per appointment, for its first person (see guest_price_cents) · rental: per item per period - guest_price_cents (integer | null): appointment: what each additional guest in a party adds; null (the default) charges each the full price, 0 makes them free - deposit_cents (integer | null): A deposit guests pay at booking where they pay online, in the currency's minor units (at most the total); the rest is due at the start. Null: the whole total - deposit_percent (integer | null): A deposit as a percent of the total, 1 to 99, paid at booking where guests pay online; null: the whole total - slot_interval_minutes (integer | null, required): Minutes between start times; null means back to back - buffer_minutes (integer, required) - min_notice_minutes (integer, required) - max_advance_days (integer, required) - max_periods (integer, required): Rentals: the most periods one booking can span - active (boolean, required): false pauses booking: guests and agents can't book it, and it stays in your dashboard - metadata (any, required): Free-form JSON object for your own integrations - lat (number | null): The meeting point's latitude, for its map link and the weather call - lon (number | null) - place_id (string | null): Google Maps' place ID for the location, which the guest's map link opens - gauge_site (string | null): A USGS river gauge's site number - schedule (hours | calendar | null): An appointment's: weekly hours or calendar entries; null for other kinds - waiver_required (boolean): Each person booked signs your waiver (waiver.get) on their phone before they come - waitlist_enabled (boolean): A full time keeps a waitlist that guests join, emailed when a place opens (waitlist_list). Switched off, everyone waiting comes off and is emailed - course (boolean): A class sold as a course: availability.get lists each calendar entry that ends as one slot, and bookings.create takes its series_id to book every time of it - questions (object[]): What guests answer as they book, in this order: ask the guest, then pass the answers to bookings.create as answers, keyed by each question's id - questions[].id (string, required): bookings.create takes the answer to this question under this id - questions[].label (string, required): The question as guests read it - questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - questions[].options (string[]): A choice's options: its answer is one of them, as listed - questions[].required (boolean, required): Guests must answer it to book online - photo_url (string | null): Its photo, at the top of its card on the booking page: a JPEG's absolute URL, or null without one. Read-only: photos are uploaded in the dashboard (the offering's Photo) - created_at (string, required): ISO 8601 timestamp (UTC) ### offerings_update: PATCH /offerings/{id} Update an offering. Set active: false to pause booking; it stays in your dashboard. Setting waitlist_enabled false takes everyone waiting for its times off the waitlist and emails each of them that it closed. Request: - id (path, string · uuid, required) - name (body, string · ≤ 120 chars) - description (body, string · ≤ 2000 chars) - location (body, string · ≤ 500 chars): Where it meets, as guests read it, with a Google Maps link: an address, a place with its town, or GPS coordinates ("45.6770, -111.0429"). Or an https meeting link (Zoom, Meet, Teams) for an offering online: guests get Join instead of a map, and its times on their own clock - duration_minutes (body, integer · 5–43200): Length of a class session or appointment, or of one rental period (1440 = a day) - capacity (body, integer · 1–10000): class: seats per session · appointment: parallel bookings per slot · rental: items in stock - max_per_booking (body, integer · 1–10000): Most seats, people or items in one booking. An appointment is one-on-one at 1 (its default); more lets a guest book for a party - price_cents (body, integer · ≥ 0): class: per seat · appointment: per appointment, for its first person (see guest_price_cents) · rental: per item per period - guest_price_cents (body, integer | null): appointment: what each additional guest in a party adds; null (the default) charges each the full price, 0 makes them free - deposit_cents (body, integer | null): A deposit to hold a place, in the currency's minor units: where guests pay online at booking, they pay this much (at most the total) and the rest at the start. Null (the default) takes the whole total. One or the other with deposit_percent: setting one clears the other, both at once is 400 deposit_conflict - deposit_percent (body, integer | null): A deposit as a percent of the total, 1 to 99, rounded half up to a whole minor unit (after any promo code). Null (the default) takes the whole total - slot_interval_minutes (body, integer | null): Minutes between start times; null means back to back - buffer_minutes (body, integer · 0–1440): Gap between bookings: minutes kept free before and after each one, for rentals and appointments on weekly hours (a calendar's times keep none) - min_notice_minutes (body, integer · 0–43200): When booking closes: how many minutes before a time starts (0: open until it starts) - max_advance_days (body, integer · 1–730) - max_periods (body, integer · 1–60): Rentals: the most periods one booking can span - active (body, boolean): false pauses booking: guests and agents can't book it, and it stays in your dashboard - metadata (body, object): Free-form JSON for your own integrations - lat (body, number | null): The meeting point's latitude, for its map link and the weather call. A new location without lat and lon sets them from coordinates typed in it, or clears them - lon (body, number | null): The meeting point's longitude - place_id (body, string | null): Google Maps' place ID for the location, which the guest's map link opens; the dashboard's Location search sets it, and a new location without it clears it - gauge_site (body, string | null): A USGS river gauge's site number (e.g. 13022500), for the river's flow - schedule (body, hours | calendar): Appointments only: open on weekly hours (offerings.set_hours) or on calendar entries (series.create), one or the other; new ones use the calendar, and it moves to hours only once its calendar has no times to come - waiver_required (body, boolean): Each person booked signs your waiver on their phone before they come: one per seat or guest, one per rental booking. Needs your waiver's text first (waiver.update; 409 waiver_missing) - waitlist_enabled (body, boolean): A full time keeps a waitlist: guests whose party doesn't fit join it from the booking page, and when a place opens everyone whose party fits is emailed at once (waitlist_list). Times on a calendar only: a class's, or an appointment's on its calendar (400 waitlist_not_supported) - questions (body, object[] · ≤ 6 items): What guests answer as they book, up to 6, in this order; the whole list replaces the last. bookings.create takes their answers keyed by each question's id - questions[].id (body, string): Keep a question's id to keep the answers given to it; a new question gets one - questions[].label (body, string · ≤ 80 chars, required): The question as guests read it, e.g. Shoe size - questions[].type (body, text | yes_no | choice, required): text: a line in their words · yes_no: yes or no · choice: one of its options - questions[].options (body, string[] · ≤ 8 items): A choice's options, 2 to 8, each once; the other types take none - questions[].required (body, boolean): Guests must answer it to book (false by default) - course (body, boolean): Classes only (409 not_a_class): sell it as a course. One booking (bookings.create's series_id) takes a seat in every time of a calendar entry from its first to come, at price_cents per seat for the whole course; a repeating entry needs ends_on. No waitlist (409 waitlist_conflict) Response 200: JSON - id (string, required) - org_id (string, required) - kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - name (string, required) - description (string, required) - location (string, required): Where it meets, as guests read it: an address, a place or GPS coordinates. Or an https meeting link for an offering online, which guests join - duration_minutes (integer, required): Length of a class session or appointment, or of one rental period (1440 = a day) - capacity (integer, required): class: seats per session · appointment: parallel bookings per slot · rental: items in stock - max_per_booking (integer, required): Most seats, people or items in one booking. An appointment is one-on-one at 1 (its default); more lets a guest book for a party - price_cents (integer, required): class: per seat · appointment: per appointment, for its first person (see guest_price_cents) · rental: per item per period - guest_price_cents (integer | null): appointment: what each additional guest in a party adds; null (the default) charges each the full price, 0 makes them free - deposit_cents (integer | null): A deposit guests pay at booking where they pay online, in the currency's minor units (at most the total); the rest is due at the start. Null: the whole total - deposit_percent (integer | null): A deposit as a percent of the total, 1 to 99, paid at booking where guests pay online; null: the whole total - slot_interval_minutes (integer | null, required): Minutes between start times; null means back to back - buffer_minutes (integer, required) - min_notice_minutes (integer, required) - max_advance_days (integer, required) - max_periods (integer, required): Rentals: the most periods one booking can span - active (boolean, required): false pauses booking: guests and agents can't book it, and it stays in your dashboard - metadata (any, required): Free-form JSON object for your own integrations - lat (number | null): The meeting point's latitude, for its map link and the weather call - lon (number | null) - place_id (string | null): Google Maps' place ID for the location, which the guest's map link opens - gauge_site (string | null): A USGS river gauge's site number - schedule (hours | calendar | null): An appointment's: weekly hours or calendar entries; null for other kinds - waiver_required (boolean): Each person booked signs your waiver (waiver.get) on their phone before they come - waitlist_enabled (boolean): A full time keeps a waitlist that guests join, emailed when a place opens (waitlist_list). Switched off, everyone waiting comes off and is emailed - course (boolean): A class sold as a course: availability.get lists each calendar entry that ends as one slot, and bookings.create takes its series_id to book every time of it - questions (object[]): What guests answer as they book, in this order: ask the guest, then pass the answers to bookings.create as answers, keyed by each question's id - questions[].id (string, required): bookings.create takes the answer to this question under this id - questions[].label (string, required): The question as guests read it - questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - questions[].options (string[]): A choice's options: its answer is one of them, as listed - questions[].required (boolean, required): Guests must answer it to book online - photo_url (string | null): Its photo, at the top of its card on the booking page: a JPEG's absolute URL, or null without one. Read-only: photos are uploaded in the dashboard (the offering's Photo) - created_at (string, required): ISO 8601 timestamp (UTC) ### offerings_delete: DELETE /offerings/{id} Delete an offering. With upcoming bookings, pass cancel_bookings: true: they're cancelled (guests emailed, online payments refunded in full) and past bookings stay on record. Returns { cancelled, refunded, refunding, refund_failed }. Request: - id (path, string · uuid, required) - cancel_bookings (query, boolean): Required when the offering has upcoming bookings or live holds; otherwise the delete answers 409 with what it would cancel Response 200: JSON - cancelled (integer, required): Upcoming bookings and holds cancelled - refunded (integer, required): Online payments Stripe confirmed refunded in full - refunding (integer, required): Refunds still on their way: Stripe hasn't confirmed them yet - refund_failed (integer, required): Refunds that failed: each booking says why in refund_error ### offerings_get_hours: GET /offerings/{id}/hours Weekly opening hours of an appointment or rental, in the org's local time Request: - id (path, string · uuid, required) Response 200: JSON - data (object[], required) - data[].weekday (integer, required): 0 = Sunday … 6 = Saturday - data[].start_time (string, required): Local wall-clock time, HH:MM:SS - data[].end_time (string, required): Local wall-clock time, HH:MM:SS ### offerings_set_hours: PUT /offerings/{id}/hours Replace weekly opening hours of a rental or an appointment on weekly hours, e.g. [{ weekday: 6, start_time: '08:00', end_time: '16:00' }] Request: - id (path, string · uuid, required) - hours (body, object[] · ≤ 50 items, required) - hours[].weekday (body, integer · 0–6, required): 0 = Sunday … 6 = Saturday - hours[].start_time (body, string, required) - hours[].end_time (body, string, required) Response 200: JSON - data (object[], required) - data[].weekday (integer, required): 0 = Sunday … 6 = Saturday - data[].start_time (string, required): Local wall-clock time, HH:MM:SS - data[].end_time (string, required): Local wall-clock time, HH:MM:SS ## Availability ### availability_get: GET /offerings/{id}/availability Bookable slots with remaining capacity between two local dates (default: the next 14 days) Request: - id (path, string · uuid, required) - from (query, string · date): Local calendar date (YYYY-MM-DD) in the org's time zone - to (query, string · date): Local calendar date (YYYY-MM-DD) in the org's time zone Response 200: JSON - timezone (string, required): The org's time zone; from and to are local dates in it - data (object[], required) - data[].starts_at (string, required): ISO 8601 timestamp (UTC) - data[].ends_at (string, required): ISO 8601 timestamp (UTC) - data[].capacity (integer, required) - data[].remaining (integer, required): What's left to book: seats, parallel slots or items; a course's, the seats left in its fullest time - data[].session_id (string): Classes only: pass it to bookings_create - data[].series_id (string): A course only: the entry it books whole; pass it to bookings_create as series_id - data[].sessions (integer): A course only: how many times it has to come, from starts_at to the last's end (ends_at) - data[].repeat (string): A course only: how its times repeat, as its entry's repeat ## Series ### series_list: GET /series List an offering's calendar entries; each makes the sessions (times) it repeats as, listed by sessions.list Request: - offering_id (query, string · uuid, required) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].offering_id (string, required) - data[].starts_on (string, required): The first time's local date - data[].start_time (string | null, required): Local HH:MM:SS; null with end_time null is all day - data[].end_time (string | null, required) - data[].span_days (integer, required): Days from a time's date to the date it ends - data[].repeat (none | daily | weekly | monthly | yearly | weekdays, required): none · daily · weekly (its first date's weekday) · monthly (that weekday of the month, e.g. the last Tuesday) · yearly · weekdays (Monday to Friday) - data[].capacity (integer | null, required): A class's seats for these times; null uses the class's - data[].ends_on (string | null): A repeat's last local date, that day included; null repeats on - data[].made_until (string, required): Its sessions exist through this local date; repeats are kept about a year ahead - data[].teacher (object | null): Who teaches it; null for nobody - data[].created_at (string, required): ISO 8601 timestamp (UTC) ### series_create: POST /series Add times to a class's calendar, or a calendar appointment's: a date, a start and end (or all day, or overnight), how it repeats and who teaches. Its sessions are made about a year ahead. Request: - starts_on (body, string · date, required): The first time's local date (YYYY-MM-DD) in the org's time zone - start_time (body, string | null): Local start, HH:MM. Leave start_time and end_time out for all day - end_time (body, string | null): Local end, HH:MM; before the start with span_days 1 runs overnight - span_days (body, integer · 0–30): Days from a time's date to the date it ends (default 0): 1 runs overnight; all day, the extra whole days - repeat (body, none | daily | weekly | monthly | yearly | weekdays): How it repeats (default none) - capacity (body, integer | null): Classes only: seats for these times; null uses the class's - teacher (body, string | null): Who teaches it: a member's user id (Settings → Team); null for nobody. Anyone not on your team answers 400 not_a_member. Copied to each of its times; a change reaches every time to come - ends_on (body, string | null): A repeat's last local date, that day included; null (the default) repeats on. A course's repeating entry needs one (409 invalid_entry) - offering_id (body, string · uuid, required) Response 201: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - starts_on (string, required): The first time's local date - start_time (string | null, required): Local HH:MM:SS; null with end_time null is all day - end_time (string | null, required) - span_days (integer, required): Days from a time's date to the date it ends - repeat (none | daily | weekly | monthly | yearly | weekdays, required): none · daily · weekly (its first date's weekday) · monthly (that weekday of the month, e.g. the last Tuesday) · yearly · weekdays (Monday to Friday) - capacity (integer | null, required): A class's seats for these times; null uses the class's - ends_on (string | null): A repeat's last local date, that day included; null repeats on - made_until (string, required): Its sessions exist through this local date; repeats are kept about a year ahead - teacher (object | null): Who teaches it; null for nobody - created_at (string, required): ISO 8601 timestamp (UTC) ### series_update: PATCH /series/{id} Change all of an entry's times: future ones nobody booked are remade from it, booked ones keep their time. A new teacher teaches every time to come Request: - id (path, string · uuid, required) - starts_on (body, string · date): The first time's local date (YYYY-MM-DD) in the org's time zone - start_time (body, string | null): Local start, HH:MM. Leave start_time and end_time out for all day - end_time (body, string | null): Local end, HH:MM; before the start with span_days 1 runs overnight - span_days (body, integer · 0–30): Days from a time's date to the date it ends (default 0): 1 runs overnight; all day, the extra whole days - repeat (body, none | daily | weekly | monthly | yearly | weekdays): How it repeats (default none) - capacity (body, integer | null): Classes only: seats for these times; null uses the class's - teacher (body, string | null): Who teaches it: a member's user id (Settings → Team); null for nobody. Anyone not on your team answers 400 not_a_member. Copied to each of its times; a change reaches every time to come - ends_on (body, string | null): A repeat's last local date, that day included; null (the default) repeats on. A course's repeating entry needs one (409 invalid_entry) Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - starts_on (string, required): The first time's local date - start_time (string | null, required): Local HH:MM:SS; null with end_time null is all day - end_time (string | null, required) - span_days (integer, required): Days from a time's date to the date it ends - repeat (none | daily | weekly | monthly | yearly | weekdays, required): none · daily · weekly (its first date's weekday) · monthly (that weekday of the month, e.g. the last Tuesday) · yearly · weekdays (Monday to Friday) - capacity (integer | null, required): A class's seats for these times; null uses the class's - ends_on (string | null): A repeat's last local date, that day included; null repeats on - made_until (string, required): Its sessions exist through this local date; repeats are kept about a year ahead - teacher (object | null): Who teaches it; null for nobody - created_at (string, required): ISO 8601 timestamp (UTC) ### series_delete: DELETE /series/{id} Remove an entry and its future times; past ones stay on record. If any is booked, pass cancel_bookings: true: they're cancelled and their guests emailed. Returns { cancelled }. Request: - id (path, string · uuid, required) - cancel_bookings (query, boolean): Required when any of its future times is booked; otherwise the delete answers 409 Response 200: JSON - cancelled (integer, required): Booked times cancelled ## Sessions ### sessions_list: GET /sessions List sessions, the times on a class's calendar (or a calendar appointment's), with what's booked in each and who teaches it Request: - offering_id (query, string · uuid) - from (query, string): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - to (query, string): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - status (query, scheduled | cancelled) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].offering_id (string, required) - data[].starts_at (string, required): ISO 8601 timestamp (UTC) - data[].ends_at (string, required): ISO 8601 timestamp (UTC) - data[].capacity (integer | null, required): Seats for this session; null means the class's capacity - data[].status (scheduled | cancelled, required) - data[].series_id (string | null): The calendar entry it's a time of; null when scheduled on its own - data[].occurs_on (string | null): Its entry's local date for it - data[].teacher (object | null): Who teaches it; null for nobody - data[].created_at (string, required): ISO 8601 timestamp (UTC) - data[].booked (integer, required): Seats booked in a class; bookings at the time in an appointment ### sessions_create: POST /sessions Schedule a class session; repeat_weeks repeats it weekly at the same local time Request: - offering_id (body, string · uuid, required) - starts_at (body, string, required): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - ends_at (body, string): When it ends, each weekly repeat as long; without it, the class's length after starts_at - repeat_weeks (body, integer · 1–52) - capacity (body, integer | null): Override the class's seats - teacher (body, string | null): Who teaches it: a member's user id (Settings → Team); null for nobody. Anyone not on your team answers 400 not_a_member Response 201: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].offering_id (string, required) - data[].starts_at (string, required): ISO 8601 timestamp (UTC) - data[].ends_at (string, required): ISO 8601 timestamp (UTC) - data[].capacity (integer | null, required): Seats for this session; null means the class's capacity - data[].status (scheduled | cancelled, required) - data[].series_id (string | null): The calendar entry it's a time of; null when scheduled on its own - data[].occurs_on (string | null): Its entry's local date for it - data[].teacher (object | null): Who teaches it; null for nobody - data[].created_at (string, required): ISO 8601 timestamp (UTC) ### sessions_update: PATCH /sessions/{id} Move one time nobody has booked (starts_at and ends_at together), or change who teaches it (teacher); its calendar entry's other times stay. A booked one can't move, only be cancelled, but its teacher can change. Request: - id (path, string · uuid, required) - starts_at (body, string): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - ends_at (body, string): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - teacher (body, string | null): Who teaches it: a member's user id (Settings → Team); null for nobody. Anyone not on your team answers 400 not_a_member Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - capacity (integer | null, required): Seats for this session; null means the class's capacity - status (scheduled | cancelled, required) - series_id (string | null): The calendar entry it's a time of; null when scheduled on its own - occurs_on (string | null): Its entry's local date for it - teacher (object | null): Who teaches it; null for nobody - created_at (string, required): ISO 8601 timestamp (UTC) ### sessions_cancel: POST /sessions/{id}/cancel Cancel one time and every booking in it; its guests are emailed. With guests: choose, each guest picks another time of the offering (or a refund) on their booking page within 7 days instead. On a time already called off, guests: refund cancels and refunds whoever is still picking; again, it changes nothing Request: - id (path, string · uuid, required) - guests (body, refund | choose): refund (default): cancel every booking, refunding what was paid online. choose: holds and a reseller's bookings are cancelled; each other booking stays confirmed with choose_by, the end of the 7th day in the org's time zone, while its guest picks another time of the offering (booking.moved) or cancels. Whoever hasn't picked by then is cancelled, refunding what they paid online - note (body, string · ≤ 200 chars): A line in your words for the guests' email, such as why the time can't run Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - capacity (integer | null, required): Seats for this session; null means the class's capacity - status (scheduled | cancelled, required) - series_id (string | null): The calendar entry it's a time of; null when scheduled on its own - occurs_on (string | null): Its entry's local date for it - teacher (object | null): Who teaches it; null for nobody - created_at (string, required): ISO 8601 timestamp (UTC) ## Bookings ### bookings_list: GET /bookings List bookings filtered by time range, status, offering, customer, session or reference, soonest first (order=desc for newest first); q searches a guest's name or email, or a reference. Page with after=. Request: - from (query, string): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - to (query, string): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - status (query, held | confirmed | cancelled) - offering_id (query, string · uuid) - customer_id (query, string · uuid) - session_id (query, string · uuid) - reference (query, string · ≤ 40 chars): The booking's reference as the guest reads it, e.g. 0GWYRZ2V (any case) - q (query, string · ≤ 80 chars): Any part of a guest's name or email, in any case, or a booking's reference - order (query, asc | desc) - limit (query, integer · 1–500) - after (query, string · uuid): A booking's id: the page continues with those after it, in the same order (pass next_after) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].offering_id (string, required) - data[].session_id (string | null, required): Classes only; a course's, the first time it was booked from - data[].series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - data[].customer_id (string, required) - data[].starts_at (string, required): ISO 8601 timestamp (UTC) - data[].ends_at (string, required): ISO 8601 timestamp (UTC) - data[].quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - data[].total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - data[].promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - data[].discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - data[].gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - data[].gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - data[].reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - data[].status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - data[].source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - data[].notes (string, required) - data[].answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - data[].metadata (any, required): Free-form JSON object for your own integrations - data[].cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - data[].created_at (string, required): ISO 8601 timestamp (UTC) - data[].expires_at (string | null, required): Held bookings: when the hold stops keeping its place - data[].handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - data[].checkout_url (string | null, required): Stripe Checkout for a hold being paid online - data[].paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - data[].paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - data[].payment_intent_id (string | null, required): The Stripe payment, when paid online - data[].charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - data[].refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - data[].refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - data[].refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - data[].refund_failed_at (string | null, required): When the last try at the refund failed - data[].refund_error (string | null, required): Why the refund failed, as Stripe said - data[].refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - data[].guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - data[].nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - data[].choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - data[].waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - data[].waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - data[].confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - data[].updated_at (string | null): When it last changed; null on bookings older than this field - data[].reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - data[].cancel_reason (string | null): Why a reseller cancelled it, in its words - data[].checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - data[].no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - data[].previous (object): bookings.move: where the booking was - data[].previous.starts_at (string, required): ISO 8601 timestamp (UTC) - data[].previous.ends_at (string, required): ISO 8601 timestamp (UTC) - data[].previous.session_id (string | null, required) - data[].offering (object, required) - data[].offering.id (string, required) - data[].offering.name (string, required) - data[].offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - data[].offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - data[].offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - data[].offering.questions[].label (string, required): The question as guests read it - data[].offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - data[].offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - data[].offering.questions[].required (boolean, required): Guests must answer it to book online - data[].customer (object, required) - data[].customer.id (string, required) - data[].customer.name (string, required) - data[].customer.email (string, required) - data[].customer.phone (string, required) - next_after (string | null, required): Pass as after= for the next page; null after the last ### bookings_get: GET /bookings/{id} Get one booking with its offering and customer, and how its waiver stands Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ### bookings_create: POST /bookings Book a slot from availability.get (classes need session_id, a course its series_id; appointments and rentals need starts_at). Pass hold_minutes to hold it instead, and idempotency_key so retries never book twice. Request: - offering_id (body, string · uuid, required) - session_id (body, string · uuid) - series_id (body, string · uuid): A course (offering course: true): the entry availability.get gives, booked whole from its first time to come - starts_at (body, string): ISO 8601 instant, e.g. 2026-10-03T15:00:00Z - quantity (body, integer · 1–10000): class: seats · appointment: people, 1 for one-on-one · rental: items - periods (body, integer · 1–60): Rentals: how many periods (e.g. days) - customer_id (body, string · uuid) - customer (body, object): Matched by email; created if new - customer.email (body, string · email, required) - customer.name (body, string · ≤ 120 chars) - customer.phone (body, string · ≤ 40 chars) - notes (body, string · ≤ 2000 chars) - answers (body, object): Answers to the offering's questions (offerings.get), keyed by each question's id: text, a choice's option exactly as listed, or true/false for yes_no. A required one left out answers 400 answers_required with its question_id - promo_code (body, string · ≤ 20 chars): A promo code the guest gave, in any case: taken off total_cents, or refused with 400 code_invalid, code_expired or code_used_up - gift_card_code (body, string · ≤ 40 chars): A gift card's code the guest gave, in any case, spaced or not: it pays what's due at booking (after promo_code, and the offering's deposit where it asks one), all it has at most, and the booking keeps gift_card_id and gift_cents. Refused with 400 gift_card_invalid or gift_card_empty, or 409 gift_card_short when its balance moved - hold_minutes (body, integer · 5–1440): Hold the place this many minutes (status held) instead of confirming; then call bookings.confirm - idempotency_key (body, string · uuid): A UUID you generate per booking: retrying with it returns the same booking instead of booking twice Response 201: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ### bookings_cancel: POST /bookings/{id}/cancel Cancel a booking or a hold and free its capacity; the guest is emailed. A payment made online (a deposit, or the whole total: charged_cents) is refunded in full, or as refund says: none, or a part (more than was paid online: 400 refund_too_large). Safe to repeat: a booking already cancelled keeps its first choice Request: - id (path, string · uuid, required) - refund (body, full | none | object): For a booking paid online: "full" (the default) refunds the whole payment, "none" keeps it, { amount_cents } refunds that part. Recorded as refund_cents. A booking not paid online ignores it Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ### bookings_confirm: POST /bookings/{id}/confirm Confirm a held booking (safe to repeat). A hold past its expires_at confirms only if its place is still free. Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ### bookings_move: POST /bookings/{id}/move Move a booking or a hold to another time of the same offering (classes: session_id; appointments and rentals: starts_at from availability.get). It keeps its reference, price and payment, the guest gets one email, and moving it to its current time changes nothing. Request: - id (path, string · uuid, required) - session_id (body, string · uuid): Classes: the session to move to - starts_at (body, string): Appointments and rentals: the new start; the booking keeps its length Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ### bookings_resend: POST /bookings/{id}/resend Email the guest their booking confirmation again, at most once a day (while its time is called off and its guest is picking another, the email asking them to pick); not for held or cancelled bookings Request: - id (path, string · uuid, required) Response 200: JSON - ok (true, required) ### bookings_set_paid: PUT /bookings/{id}/paid Mark a confirmed booking paid when the money was taken by hand (cash, a card reader), or pass paid false to take that back. It sets paid_at and paid_cents and logs booking.paid or booking.unpaid. After a deposit paid online, it records the rest paid, and paid false takes back only that rest; a payment made online stays as it is. Safe to repeat. Request: - id (path, string · uuid, required) - paid (body, boolean, required): true: the guest paid the business directly · false: undo that Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ### bookings_nudge: POST /bookings/{id}/nudge Email the guest of a lapsed, unpaid hold a link to finish booking. Once per booking: for a hold made on the booking page whose Stripe Checkout expired unpaid 10 minutes to a day ago, for a time still free, to a guest who hasn't booked since; anything else is refused with 409 not_nudgeable (already_nudged once sent), and 503 unavailable while Stripe can't be asked. It sets nudged_at and logs booking.nudged. Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ### bookings_set_attendance: POST /bookings/{id}/attendance Record who showed up: state checked_in when the guest arrives (a rental's guest: picks up), no_show once the booking's time has started and they haven't come, or none to clear either. It sets checked_in_at or no_show_at, never both, and logs booking.checked_in, booking.no_show or booking.attendance_cleared; setting what it already is changes nothing. Only a confirmed booking: a hold or a cancelled booking answers 409 not_confirmed, and a no-show before the start 409 not_started. Request: - id (path, string · uuid, required) - state (body, checked_in | no_show | none, required): checked_in: they're here · no_show: they didn't come, once the time has started · none: clear either Response 200: JSON - id (string, required) - org_id (string, required) - offering_id (string, required) - session_id (string | null, required): Classes only; a course's, the first time it was booked from - series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - customer_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - notes (string, required) - answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - metadata (any, required): Free-form JSON object for your own integrations - cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - expires_at (string | null, required): Held bookings: when the hold stops keeping its place - handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - checkout_url (string | null, required): Stripe Checkout for a hold being paid online - paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - payment_intent_id (string | null, required): The Stripe payment, when paid online - charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - refund_failed_at (string | null, required): When the last try at the refund failed - refund_error (string | null, required): Why the refund failed, as Stripe said - refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - updated_at (string | null): When it last changed; null on bookings older than this field - reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - cancel_reason (string | null): Why a reseller cancelled it, in its words - checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - previous (object): bookings.move: where the booking was - previous.starts_at (string, required): ISO 8601 timestamp (UTC) - previous.ends_at (string, required): ISO 8601 timestamp (UTC) - previous.session_id (string | null, required) - offering (object, required) - offering.id (string, required) - offering.name (string, required) - offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - offering.questions[].label (string, required): The question as guests read it - offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - offering.questions[].required (boolean, required): Guests must answer it to book online - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) ## Promo codes ### promo_codes_list: GET /promo_codes List the business's promo codes, newest first, each with how many bookings have used it Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].code (string, required): As guests give it, upper-cased: 3 to 20 letters, digits and dashes - data[].percent_off (integer | null, required): Percent off a booking's total, 1 to 100; null when it takes an amount off - data[].amount_off (integer | null, required): Off a booking's total, in the currency's minor units (cents; whole yen for zero-decimal currencies), never below zero; null when it takes a percent off - data[].offering_id (string | null, required): The one offering it's for; null for any offering - data[].max_uses (integer | null, required): How many bookings may use it; null for no limit - data[].uses (integer, required): Bookings made with it - data[].starts_at (string | null, required): It works from then; null for at once - data[].ends_at (string | null, required): It works until then; null for no end - data[].active (boolean, required): false: switched off, it can't be used - data[].created_at (string, required): ISO 8601 timestamp (UTC) ### promo_codes_create: POST /promo_codes Add a promo code guests can give as they book (bookings.create's promo_code): percent_off or amount_off a booking's total, for any offering or one, with an optional limit on uses and dates. Up to 100 per org; a code the org has already is refused with 409 code_taken Request: - code (body, string · ≤ 20 chars, required): 3 to 20 letters, digits and dashes, such as SPRING20; stored upper-cased, and guests may type it in any case - percent_off (body, integer · 1–100): Percent off the total, 1 to 100 (100 makes the booking free); or amount_off - amount_off (body, integer · ≥ 1): Off the total, in the currency's minor units (cents; whole yen for zero-decimal currencies), never below zero; or percent_off - offering_id (body, string | null): Only this offering's bookings; null (or left out) for any offering - max_uses (body, integer | null): How many bookings may use it; null (or left out) for no limit - starts_at (body, string | null): It works from then; null (or left out) for at once - ends_at (body, string | null): It stops working then; null (or left out) for no end - active (body, boolean): false adds it switched off (default true) Response 201: JSON - id (string, required) - org_id (string, required) - code (string, required): As guests give it, upper-cased: 3 to 20 letters, digits and dashes - percent_off (integer | null, required): Percent off a booking's total, 1 to 100; null when it takes an amount off - amount_off (integer | null, required): Off a booking's total, in the currency's minor units (cents; whole yen for zero-decimal currencies), never below zero; null when it takes a percent off - offering_id (string | null, required): The one offering it's for; null for any offering - max_uses (integer | null, required): How many bookings may use it; null for no limit - uses (integer, required): Bookings made with it - starts_at (string | null, required): It works from then; null for at once - ends_at (string | null, required): It works until then; null for no end - active (boolean, required): false: switched off, it can't be used - created_at (string, required): ISO 8601 timestamp (UTC) ### promo_codes_update: PATCH /promo_codes/{id} Switch a promo code on or off, or change its limit, end or offering; null opens each again. Bookings made with it keep what it took off Request: - id (path, string · uuid, required) - active (body, boolean): false switches it off: guests can't use it - max_uses (body, integer | null): How many bookings may use it; null (or left out) for no limit - ends_at (body, string | null): It stops working then; null (or left out) for no end - offering_id (body, string | null): Only this offering's bookings; null (or left out) for any offering Response 200: JSON - id (string, required) - org_id (string, required) - code (string, required): As guests give it, upper-cased: 3 to 20 letters, digits and dashes - percent_off (integer | null, required): Percent off a booking's total, 1 to 100; null when it takes an amount off - amount_off (integer | null, required): Off a booking's total, in the currency's minor units (cents; whole yen for zero-decimal currencies), never below zero; null when it takes a percent off - offering_id (string | null, required): The one offering it's for; null for any offering - max_uses (integer | null, required): How many bookings may use it; null for no limit - uses (integer, required): Bookings made with it - starts_at (string | null, required): It works from then; null for at once - ends_at (string | null, required): It works until then; null for no end - active (boolean, required): false: switched off, it can't be used - created_at (string, required): ISO 8601 timestamp (UTC) ### promo_codes_delete: DELETE /promo_codes/{id} Delete a promo code: it can't be used again, and bookings made with it keep its words (promo_code) and what it took off Request: - id (path, string · uuid, required) Response 200: JSON - ok (true, required) ## Gift cards ### gift_cards_list: GET /gift_cards List the business's gift cards, newest first, each with its code, who it's for and from, and what's left on it (balance). Page with before=. Request: - limit (query, integer · 1–500) - before (query, string · uuid): A card's id: the page continues with those made before it (pass next_before) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].code (string, required): 12 characters of Crockford base32, as made: guests give it as they book (bookings.create's gift_card_code), in any case, spaced or not - data[].amount_cents (integer, required): What it was worth when made, in the currency's minor units (cents; whole yen for zero-decimal currencies) - data[].currency (string, required): ISO 4217, lowercase: the org's when it was made - data[].for_name (string, required): Who it's for, as given; may be empty - data[].for_email (string, required): Who it's for: emailed the code when it was made - data[].from_name (string, required): Who it's from: the buyer, or your business for one you issued - data[].from_email (string, required) - data[].message (string, required): The buyer's message to who it's for, up to 300 characters; may be empty - data[].issued_by (purchase | business | null, required): purchase: bought on your booking page; business: issued by you (gift_cards_issue) - data[].checkout_session_id (string | null, required): A bought card's Stripe Checkout, on your account - data[].payment_intent_id (string | null, required): A bought card's Stripe payment, on your account - data[].created_at (string, required): ISO 8601 timestamp (UTC) - data[].balance (integer, required): What's on it: the sum of its entries, in the currency's minor units (cents; whole yen for zero-decimal currencies). Gift cards never expire - data[].available (integer, required): What it can spend now: the balance less the parts of live holds that take it once they're confirmed, in the currency's minor units (cents; whole yen for zero-decimal currencies) - next_before (string | null, required): Pass as before= for the next page; null after the last ### gift_cards_get: GET /gift_cards/{id} Get one gift card by its id or its code (in any case, spaced or not), with every change to what's on it: purchase or issue, redeems, refunds and adjusts Request: - id (path, string · ≤ 40 chars, required): The card's id, or its code Response 200: JSON - id (string, required) - org_id (string, required) - code (string, required): 12 characters of Crockford base32, as made: guests give it as they book (bookings.create's gift_card_code), in any case, spaced or not - amount_cents (integer, required): What it was worth when made, in the currency's minor units (cents; whole yen for zero-decimal currencies) - currency (string, required): ISO 4217, lowercase: the org's when it was made - for_name (string, required): Who it's for, as given; may be empty - for_email (string, required): Who it's for: emailed the code when it was made - from_name (string, required): Who it's from: the buyer, or your business for one you issued - from_email (string, required) - message (string, required): The buyer's message to who it's for, up to 300 characters; may be empty - issued_by (purchase | business | null, required): purchase: bought on your booking page; business: issued by you (gift_cards_issue) - checkout_session_id (string | null, required): A bought card's Stripe Checkout, on your account - payment_intent_id (string | null, required): A bought card's Stripe payment, on your account - created_at (string, required): ISO 8601 timestamp (UTC) - balance (integer, required): What's on it: the sum of its entries, in the currency's minor units (cents; whole yen for zero-decimal currencies). Gift cards never expire - available (integer, required): What it can spend now: the balance less the parts of live holds that take it once they're confirmed, in the currency's minor units (cents; whole yen for zero-decimal currencies) - entries (object[], required): Every change to what's on it, oldest first - entries[].id (string, required) - entries[].booking_id (string | null, required): The booking a redeem or a refund was for - entries[].cents (integer, required): Signed, in the currency's minor units (cents; whole yen for zero-decimal currencies): a purchase, an issue and a refund add, a redeem takes off, an adjust either - entries[].kind (purchase | issue | redeem | refund | adjust, required): redeem: a booking was confirmed with it; refund: that booking was cancelled; adjust: you fixed the balance - entries[].note (string, required): An adjust's reason - entries[].created_at (string, required): ISO 8601 timestamp (UTC) ### gift_cards_issue: POST /gift_cards Issue a gift card by hand, for goodwill or a refund as credit, on any plan: it's from your business, and who it's for is emailed the code. Logs gift_card.issued Request: - amount_cents (body, integer · 1–10000000, required): What it's worth, in the currency's minor units (cents; whole yen for zero-decimal currencies), in your currency - for_name (body, string · ≤ 120 chars): Who it's for, as the email greets them - for_email (body, string · email, required): Who it's for: emailed the code - message (body, string · ≤ 300 chars): A line for them in the email Response 201: JSON - id (string, required) - org_id (string, required) - code (string, required): 12 characters of Crockford base32, as made: guests give it as they book (bookings.create's gift_card_code), in any case, spaced or not - amount_cents (integer, required): What it was worth when made, in the currency's minor units (cents; whole yen for zero-decimal currencies) - currency (string, required): ISO 4217, lowercase: the org's when it was made - for_name (string, required): Who it's for, as given; may be empty - for_email (string, required): Who it's for: emailed the code when it was made - from_name (string, required): Who it's from: the buyer, or your business for one you issued - from_email (string, required) - message (string, required): The buyer's message to who it's for, up to 300 characters; may be empty - issued_by (purchase | business | null, required): purchase: bought on your booking page; business: issued by you (gift_cards_issue) - checkout_session_id (string | null, required): A bought card's Stripe Checkout, on your account - payment_intent_id (string | null, required): A bought card's Stripe payment, on your account - created_at (string, required): ISO 8601 timestamp (UTC) - balance (integer, required): What's on it: the sum of its entries, in the currency's minor units (cents; whole yen for zero-decimal currencies). Gift cards never expire - available (integer, required): What it can spend now: the balance less the parts of live holds that take it once they're confirmed, in the currency's minor units (cents; whole yen for zero-decimal currencies) ### gift_cards_adjust: POST /gift_cards/{id}/adjust Fix a gift card's balance by a signed amount, in the currency's minor units (cents; whole yen for zero-decimal currencies), with your reason: an entry of kind adjust, and gift_card.adjusted. It can't go below zero (409 gift_card_short) Request: - id (path, string · uuid, required) - amount_cents (body, integer · -10000000–10000000, required): More than zero adds to the balance, less takes off it - reason (body, string · ≤ 200 chars, required): Why, kept on the entry Response 200: JSON - id (string, required) - org_id (string, required) - code (string, required): 12 characters of Crockford base32, as made: guests give it as they book (bookings.create's gift_card_code), in any case, spaced or not - amount_cents (integer, required): What it was worth when made, in the currency's minor units (cents; whole yen for zero-decimal currencies) - currency (string, required): ISO 4217, lowercase: the org's when it was made - for_name (string, required): Who it's for, as given; may be empty - for_email (string, required): Who it's for: emailed the code when it was made - from_name (string, required): Who it's from: the buyer, or your business for one you issued - from_email (string, required) - message (string, required): The buyer's message to who it's for, up to 300 characters; may be empty - issued_by (purchase | business | null, required): purchase: bought on your booking page; business: issued by you (gift_cards_issue) - checkout_session_id (string | null, required): A bought card's Stripe Checkout, on your account - payment_intent_id (string | null, required): A bought card's Stripe payment, on your account - created_at (string, required): ISO 8601 timestamp (UTC) - balance (integer, required): What's on it: the sum of its entries, in the currency's minor units (cents; whole yen for zero-decimal currencies). Gift cards never expire - available (integer, required): What it can spend now: the balance less the parts of live holds that take it once they're confirmed, in the currency's minor units (cents; whole yen for zero-decimal currencies) ## Waiver ### waiver_get: GET /waiver Your waiver: the title and text each person on a booking signs before they come (the booker as they book online, the rest from the booking's signing link), and its version. body null: you have none, and nobody is asked to sign Response 200: JSON - id (string | null, required): This version's id; null before the first save - title (string | null, required): e.g. Release of liability; null when you have no waiver - body (string | null, required): The text each person signs: plain text, a blank line between paragraphs. null: you have no waiver and nobody is asked to sign - version (integer, required): Goes up by one with each save; a signature keeps the version it signed. 0 before the first - created_at (string | null, required): When this version was saved ### waiver_update: PUT /waiver Save your waiver's title and text as a new version (each signature keeps the version it signed), or pass body null to remove it, which stops every offering asking for it. Switch it on per offering with offerings.update waiver_required. daybooked stores the text and the signatures; it doesn't write or review your waiver Request: - title (body, string · ≤ 120 chars): Required with a body, e.g. Release of liability - body (body, string | null, required): Plain text, a blank line between paragraphs; null removes the waiver Response 200: JSON - id (string | null, required): This version's id; null before the first save - title (string | null, required): e.g. Release of liability; null when you have no waiver - body (string | null, required): The text each person signs: plain text, a blank line between paragraphs. null: you have no waiver and nobody is asked to sign - version (integer, required): Goes up by one with each save; a signature keeps the version it signed. 0 before the first - created_at (string | null, required): When this version was saved ## Waiver signatures ### waiver_signatures_list: GET /waiver_signatures Who signed your waiver for a booking (booking_id), or for everyone in a class session (session_id), oldest first, each with the version signed. A booking's waiver { needed, signed } counts them Request: - booking_id (query, string · uuid) - session_id (query, string · uuid) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].booking_id (string, required) - data[].waiver_id (string, required): The waiver version signed - data[].version (integer, required): The version signed - data[].name (string, required): The signer's full name - data[].for_minor (string | null, required): The child's full name, when a parent or guardian signed for them - data[].signed_at (string, required): When it was signed, by daybooked's clock - data[].with_booking (boolean, required): true: the booker signed it as they booked, on your booking page or widget; false: someone signed from the booking's signing link ## Waitlist ### waitlist_list: GET /waitlist Who is waiting for a full time, soonest time first, then in the order they joined: for one time (session_id), an offering's times to come (offering_id), or every time to come. Each entry has the guest, their places and when they were last told a place opened Request: - session_id (query, string · uuid) - offering_id (query, string · uuid) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].session_id (string, required): The time they're waiting for - data[].offering_id (string, required) - data[].starts_at (string, required): ISO 8601 timestamp (UTC) - data[].ends_at (string, required): ISO 8601 timestamp (UTC) - data[].places (integer, required): Their party: seats, guests or items - data[].joined_at (string, required): ISO 8601 timestamp (UTC) - data[].told_at (string | null, required): When they were last told a place opened; null until they are. A guest is told at most once every 6 hours, 3 times in all - data[].customer (object, required) - data[].customer.id (string, required) - data[].customer.name (string, required) - data[].customer.email (string, required) - data[].customer.phone (string, required) ### waitlist_add: POST /waitlist Put a guest on a full time's waitlist by hand, such as a caller: by session_id, or offering_id with starts_at. Its offering's waitlist must be on (offerings.update waitlist_enabled; 409 waitlist_off). Nothing is held or charged. The guest is emailed that they're on it, with a link to leave; when a place opens, everyone waiting whose party fits is emailed at once and the first to book gets it. A party that fits now is refused with 409 has_room (book it instead), and one the time could never take with 400 too_many_places. The same guest again changes their places. The answer says what changed and whether they were emailed Request: - session_id (body, string · uuid): The time: a class's session_id from availability_get, or any time's from sessions_list - offering_id (body, string · uuid) - starts_at (body, string): With offering_id, the time's start: how an appointment's calendar time is named - places (body, integer · 1–10000, required): Their party: seats, guests or items - customer (body, object, required) - customer.email (body, string · email, required) - customer.name (body, string · ≤ 120 chars) - customer.phone (body, string · ≤ 40 chars) Response 201: JSON - id (string, required) - session_id (string, required): The time they're waiting for - offering_id (string, required) - starts_at (string, required): ISO 8601 timestamp (UTC) - ends_at (string, required): ISO 8601 timestamp (UTC) - places (integer, required): Their party: seats, guests or items - joined_at (string, required): ISO 8601 timestamp (UTC) - told_at (string | null, required): When they were last told a place opened; null until they are. A guest is told at most once every 6 hours, 3 times in all - customer (object, required) - customer.id (string, required) - customer.name (string, required) - customer.email (string, required) - customer.phone (string, required) - change (joined | rejoined | updated | same, required): joined: put on; rejoined: put back after leaving; updated: their places changed; same: already waiting as asked - emailed (boolean, required): Whether they were emailed that they're on it: false when nothing new was joined, or when their inbox's daily cap for waitlist mail held it back ### waitlist_offer: POST /waitlist/offer Tell everyone waiting for a full time (session_id) about another time of the same offering (starts_at), as Fill the day does when it opens the next day's: each guest whose party fits it now is emailed once, with a link that books it for their party. They stay on the waitlist they joined. 404 not_found when the offering has no time starting then. Answers how many were emailed; offering the same time again emails nobody new Request: - session_id (body, string · uuid, required): The full time they're waiting for - starts_at (body, string, required): The other time's start, a time of the same offering Response 200: JSON - told (integer, required): Guests emailed about it now ### waitlist_remove: DELETE /waitlist/{id} Take a guest off a waitlist; they aren't emailed. Logs waitlist.left with reason removed. Removing twice changes nothing Request: - id (path, string · uuid, required) Response 200: JSON - ok (true, required) ## Conversations ### conversations_list: GET /conversations List conversations with guests, the ones waiting on a reply first, each with its guest, last message and booking chip (filter by status, unread, a search q, or customer_id for one guest's) Request: - status (query, open | done) - unread (query, boolean) - q (query, string · ≤ 200 chars): Matches the guest's name or email, or words in the messages - customer_id (query, string · uuid) - limit (query, integer · 1–500) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].status (open | done, required) - data[].last_message_at (string, required): ISO 8601 timestamp (UTC) - data[].outfitter_read_at (string | null, required): ISO 8601 timestamp (UTC) - data[].guest_read_at (string | null, required): ISO 8601 timestamp (UTC) - data[].snoozed_until (string | null, required): ISO 8601 timestamp (UTC) - data[].created_at (string, required): ISO 8601 timestamp (UTC) - data[].unread (boolean, required): A guest message is newer than outfitter_read_at - data[].needs_reply (boolean, required): The guest wrote last - data[].customer (object | null, required): Null on a pre-sale question - data[].last_message (object | null, required) - data[].booking (object | null, required): The guest's next upcoming booking, else their latest ### conversations_get: GET /conversations/{id} Get a conversation with its thread oldest first: messages, notes, and the guest's booking events as system rows Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - status (open | done, required) - last_message_at (string, required): ISO 8601 timestamp (UTC) - outfitter_read_at (string | null, required): ISO 8601 timestamp (UTC) - guest_read_at (string | null, required): ISO 8601 timestamp (UTC) - snoozed_until (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - unread (boolean, required): A guest message is newer than outfitter_read_at - needs_reply (boolean, required): The guest wrote last - customer (object | null, required): Null on a pre-sale question - last_message (object | null, required) - booking (object | null, required): The guest's next upcoming booking, else their latest - thread (object | object[], required) ### conversations_update: PATCH /conversations/{id} Mark a conversation done or open again; read: true once the guest's messages have been seen Request: - id (path, string · uuid, required) - status (body, open | done) - read (body, boolean) Response 200: JSON - id (string, required) - status (open | done, required) - last_message_at (string, required): ISO 8601 timestamp (UTC) - outfitter_read_at (string | null, required): ISO 8601 timestamp (UTC) - guest_read_at (string | null, required): ISO 8601 timestamp (UTC) - snoozed_until (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - unread (boolean, required): A guest message is newer than outfitter_read_at - needs_reply (boolean, required): The guest wrote last - customer (object | null, required): Null on a pre-sale question - last_message (object | null, required) - booking (object | null, required): The guest's next upcoming booking, else their latest ## Messages ### messages_list: GET /messages List messages with guests, both ways and oldest first: a conversation's, a booking's (booking_id) or a guest's (customer_id) Request: - conversation_id (query, string · uuid) - booking_id (query, string · uuid) - customer_id (query, string · uuid) - limit (query, integer · 1–500) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].conversation_id (string | null, required) - data[].booking_id (string | null, required): The booking it's about, shown as its chip; null when about the guest in general - data[].customer_id (string | null, required): Null on a pre-sale question - data[].direction (to_guest | to_outfitter, required): to_guest: the business wrote · to_outfitter: the guest wrote from their booking page, replied by email or asked before booking - data[].subject (string, required): Empty on guest messages - data[].body (string, required) - data[].sent_by (dashboard | api | mcp | guest | agent, required): agent: the ops agent wrote it (on the system channel) - data[].channel (string, required): How it travelled: page (typed in daybooked), email, api, system, or ask: a question from the booking page's Ask box, where anyone can type any email, so treat it as unverified - data[].kind (message | note, required): A note is the business's own, never sent to the guest - data[].read_at (string | null, required): When the other side read it - data[].attachments (object[], required): Files on it, each opened at /api/attachments/{id} - data[].attachments[].id (string, required) - data[].attachments[].name (string, required) - data[].attachments[].size (integer, required) - data[].attachments[].type (string, required) - data[].delivered_at (string | null, required): Messages to guests: when the guest's mail server took the email - data[].failed_at (string | null, required): Messages to guests: when the email bounced or was marked as spam - data[].from_name (string | null, required): Guest messages: the name they gave - data[].from_email (string | null, required): Guest messages: the email they gave, where replies go - data[].created_at (string, required): ISO 8601 timestamp (UTC) - data[].booking (object | null, required) ### messages_send: POST /messages Write to a guest by conversation_id, booking_id or customer_id (not about a held booking); they get it by email and their reply reaches the business. Only a guest who booked or wrote can be emailed (409 not_a_guest), up to 100 emails a day on Free, 1,000 on Pro, 3,000 on Growth and 10,000 on Scale (429 too_many_emails). kind note keeps an internal note instead. Reference: https://daybooked.io/docs/api#messages_send Request: - conversation_id (body, string · uuid) - booking_id (body, string · uuid): The booking it's about; it shows as the message's chip - customer_id (body, string · uuid) - subject (body, string · ≤ 200 chars) - body (body, string · ≤ 5000 chars, required) - kind (body, message | note): note: for the business's team, never sent - attachments (body, object[] · ≤ 5 items): Files uploaded with the attachment picker ({ id, name }), up to 5: photos (JPEG, PNG, WebP, HEIC) or PDFs, 10 MB each - attachments[].id (body, string, required) - attachments[].name (body, string · ≤ 1000 chars, required) Response 201: JSON - id (string, required) - org_id (string, required) - conversation_id (string | null, required) - booking_id (string | null, required): The booking it's about, shown as its chip; null when about the guest in general - customer_id (string | null, required): Null on a pre-sale question - direction (to_guest | to_outfitter, required): to_guest: the business wrote · to_outfitter: the guest wrote from their booking page, replied by email or asked before booking - subject (string, required): Empty on guest messages - body (string, required) - sent_by (dashboard | api | mcp | guest | agent, required): agent: the ops agent wrote it (on the system channel) - channel (string, required): How it travelled: page (typed in daybooked), email, api, system, or ask: a question from the booking page's Ask box, where anyone can type any email, so treat it as unverified - kind (message | note, required): A note is the business's own, never sent to the guest - read_at (string | null, required): When the other side read it - attachments (object[], required): Files on it, each opened at /api/attachments/{id} - attachments[].id (string, required) - attachments[].name (string, required) - attachments[].size (integer, required) - attachments[].type (string, required) - delivered_at (string | null, required): Messages to guests: when the guest's mail server took the email - failed_at (string | null, required): Messages to guests: when the email bounced or was marked as spam - from_name (string | null, required): Guest messages: the name they gave - from_email (string | null, required): Guest messages: the email they gave, where replies go - created_at (string, required): ISO 8601 timestamp (UTC) ### messages_broadcast: POST /messages/broadcast Write to many guests, once each: everyone confirmed in a class session (target.session_id), starting on a local date across offerings (target.date), or booked ahead on an offering, or picking another time of it (target.offering_id). Returns how many were sent, skipped (erased guests) and failed; one that would pass the daily email limit is refused whole. Reference: https://daybooked.io/docs/api#messages_broadcast Request: - target (body, object | object | object, required): { session_id }, { date } (optionally with a filter) or { offering_id } - subject (body, string · ≤ 200 chars) - body (body, string · ≤ 5000 chars, required) Response 200: JSON - sent (integer, required) - skipped (integer, required) - failed (integer, required) ### messages_draft: POST /messages/draft Draft a reply in a conversation for the owner to edit and send; nothing is sent. Written from the last 10 messages and the guest's latest booking. 409 drafts_unavailable when drafting is off; 60 drafts per org in any 24 hours Request: - conversation_id (body, string · uuid, required): The conversation to draft a reply in Response 200: JSON - text (string, required): The drafted reply, plain text, to review and edit before sending ## Saved replies ### saved_replies_list: GET /saved_replies List the business's saved replies by title. With booking_id, or conversation_id (its guest and their booking under way or next), each comes with text: its body filled in, ready to send with messages_send Request: - booking_id (query, string · uuid): Fill the replies in for this booking and its guest - conversation_id (query, string · uuid): Or for this conversation's guest and their booking under way or next Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].title (string, required): What the owner picks it by - data[].body (string, required): The message as saved, with its {variables} - data[].created_at (string, required): ISO 8601 timestamp (UTC) - data[].updated_at (string, required): ISO 8601 timestamp (UTC) - data[].text (string, required): The body filled in for booking_id or conversation_id, ready for messages_send; without them only {org} is filled in ### saved_replies_create: POST /saved_replies Save a reply the business can reuse. Its body can use {first_name}, {start_time}, {offering}, {meeting_point}, {org}, {booking_link}, which saved_replies_list fills in for a guest. Reference: https://daybooked.io/docs/api#saved_replies_create Request: - title (body, string · ≤ 80 chars, required): What it's picked by, such as Directions - body (body, string · ≤ 5000 chars, required): The message. {first_name}, {start_time}, {offering}, {meeting_point}, {org}, {booking_link} are filled in for a guest when it's used Response 201: JSON - id (string, required) - org_id (string, required) - title (string, required): What the owner picks it by - body (string, required): The message as saved, with its {variables} - created_at (string, required): ISO 8601 timestamp (UTC) - updated_at (string, required): ISO 8601 timestamp (UTC) ### saved_replies_update: PATCH /saved_replies/{id} Change a saved reply's title or body. Reference: https://daybooked.io/docs/api#saved_replies_update Request: - id (path, string · uuid, required) - title (body, string · ≤ 80 chars): What it's picked by, such as Directions - body (body, string · ≤ 5000 chars): The message. {first_name}, {start_time}, {offering}, {meeting_point}, {org}, {booking_link} are filled in for a guest when it's used Response 200: JSON - id (string, required) - org_id (string, required) - title (string, required): What the owner picks it by - body (string, required): The message as saved, with its {variables} - created_at (string, required): ISO 8601 timestamp (UTC) - updated_at (string, required): ISO 8601 timestamp (UTC) ### saved_replies_delete: DELETE /saved_replies/{id} Delete a saved reply Request: - id (path, string · uuid, required) Response 200: JSON - ok (true, required) ## Automations ### automations_list: GET /automations The ops agent's automations (fill, brief, reminders; the weather call isn't available yet), each with its dial (off, ask, do_tell, do_quiet) and settings. Its guardrails (quiet hours, daily cap, refund ceiling) are on org_get Response 200: JSON - data (object[], required) - data[].automation (weather | fill | brief | reminders, required): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - data[].dial (off | ask | do_tell | do_quiet, required): off · ask: propose in the Inbox and wait · do_tell: act, then a card and a push · do_quiet: act and log - data[].settings (object, required): weather: { offerings: { : limits }, default: limits }, where limits are maxWindKn and maxGustKn (knots), maxPrecipProb (%), minTempC and maxTempC (°C), noThunder, and minFlowCfs and maxFlowCfs (river flow) · fill: { full_pct (50–100, default 80): once a class time in the next month is this full, or has people on its waitlist, open one at the same time the next day, and email whoever waits for the full one (waitlist.offer) } · brief: { see_you (default true): offer a note to everyone booked today } · reminders (dial off or do_quiet: sent on their own, outside quiet hours): { before_24h, before_2h, after_6h (needs the org's review_url), before_24h_reply_id (a saved reply sent the day before; null = ours), unpaid_hold (default false): bookings_nudge for a guest whose hold lapsed unpaid at Checkout, in an org that takes payment at booking } - data[].updated_at (string | null, required): null until it's first set ### automations_update: PATCH /automations/{automation} Turn an automation's dial, or change its settings: the fields given replace those set Request: - automation (path, weather | fill | brief | reminders, required): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - dial (body, off | ask | do_tell | do_quiet): off · ask: propose in the Inbox and wait · do_tell: act, then a card and a push · do_quiet: act and log - settings (body, object): weather: { offerings: { : limits }, default: limits }, where limits are maxWindKn and maxGustKn (knots), maxPrecipProb (%), minTempC and maxTempC (°C), noThunder, and minFlowCfs and maxFlowCfs (river flow) · fill: { full_pct (50–100, default 80): once a class time in the next month is this full, or has people on its waitlist, open one at the same time the next day, and email whoever waits for the full one (waitlist.offer) } · brief: { see_you (default true): offer a note to everyone booked today } · reminders (dial off or do_quiet: sent on their own, outside quiet hours): { before_24h, before_2h, after_6h (needs the org's review_url), before_24h_reply_id (a saved reply sent the day before; null = ours), unpaid_hold (default false): bookings_nudge for a guest whose hold lapsed unpaid at Checkout, in an org that takes payment at booking } Response 200: JSON - automation (weather | fill | brief | reminders, required): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - dial (off | ask | do_tell | do_quiet, required): off · ask: propose in the Inbox and wait · do_tell: act, then a card and a push · do_quiet: act and log - settings (object, required): weather: { offerings: { : limits }, default: limits }, where limits are maxWindKn and maxGustKn (knots), maxPrecipProb (%), minTempC and maxTempC (°C), noThunder, and minFlowCfs and maxFlowCfs (river flow) · fill: { full_pct (50–100, default 80): once a class time in the next month is this full, or has people on its waitlist, open one at the same time the next day, and email whoever waits for the full one (waitlist.offer) } · brief: { see_you (default true): offer a note to everyone booked today } · reminders (dial off or do_quiet: sent on their own, outside quiet hours): { before_24h, before_2h, after_6h (needs the org's review_url), before_24h_reply_id (a saved reply sent the day before; null = ours), unpaid_hold (default false): bookings_nudge for a guest whose hold lapsed unpaid at Checkout, in an org that takes payment at booking } - updated_at (string | null, required): null until it's first set ## Proposals ### proposals_list: GET /proposals What the ops agent proposed or did, newest first. A pending one waits for proposals_approve (which runs its actions) or proposals_dismiss. Page with before=. Request: - status (query, pending | done | failed | dismissed | expired | undone) - automation (query, weather | fill | brief | reminders): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - limit (query, integer · 1–500) - before (query, string · uuid): A proposal's id: the page continues with those made before it (pass next_before) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].automation (weather | fill | brief | reminders, required): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - data[].status (pending | done | failed | dismissed | expired | undone, required): pending waits for proposals_approve or proposals_dismiss; approving runs it, so it lands on done or failed - data[].dial (ask | do_tell | do_quiet, required): ask: it waited for a person · do_tell, do_quiet: the agent acted on its own - data[].title (string, required) - data[].day (string, required): The local date it's for - data[].session_id (string | null, required) - data[].booking_id (string | null, required) - data[].data (object, required): The brief: trips (today's sessions), unanswered threads and weather; held: "cap" or "money" when the agent waited instead of acting - data[].actions (object[], required): Registry operations, run in order as the agent - data[].actions[].kind (cancel_session | cancel_booking | move_booking | create_session | message | remind | nudge | offer_time, required) - data[].actions[].op (string, required): The operation it runs, e.g. sessions.create - data[].actions[].input (object, required): The operation's input - data[].actions[].facts (object, required): What it's about and why: the session or booking, the reason, the refund, the drafted words - data[].actions[].money (boolean): It refunds - data[].actions[].reversible (boolean): Once done, proposals_undo can reverse it - data[].actions[].result (object) - data[].actions[].result.ok (boolean, required) - data[].actions[].result.data (any) - data[].actions[].result.error (string) - data[].actions[].undo (object) - data[].actions[].undo.op (string, required) - data[].actions[].undo.input (object, required) - data[].money (boolean, required): An action refunds - data[].reversible (boolean, required): Done, and proposals_undo can reverse it - data[].expires_at (string | null, required): ISO 8601 timestamp (UTC) - data[].created_at (string, required): ISO 8601 timestamp (UTC) - data[].decided_at (string | null, required): ISO 8601 timestamp (UTC) - data[].decided_by (string | null, required): dashboard, api, mcp or agent - data[].done_at (string | null, required): ISO 8601 timestamp (UTC) - data[].error (string | null, required) - next_before (string | null, required): Pass as before= for the next page; null after the last ### proposals_approve: POST /proposals/{id}/approve Approve a pending proposal: its actions run now, in order, as the agent, stopping at the first that fails. draft rewords its message first Request: - id (path, string · uuid, required) - draft (body, object): Replaces the words of its first message or reminder - draft.subject (body, string · ≤ 200 chars) - draft.body (body, string · ≤ 5000 chars, required) Response 200: JSON - id (string, required) - automation (weather | fill | brief | reminders, required): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - status (pending | done | failed | dismissed | expired | undone, required): pending waits for proposals_approve or proposals_dismiss; approving runs it, so it lands on done or failed - dial (ask | do_tell | do_quiet, required): ask: it waited for a person · do_tell, do_quiet: the agent acted on its own - title (string, required) - day (string, required): The local date it's for - session_id (string | null, required) - booking_id (string | null, required) - data (object, required): The brief: trips (today's sessions), unanswered threads and weather; held: "cap" or "money" when the agent waited instead of acting - actions (object[], required): Registry operations, run in order as the agent - actions[].kind (cancel_session | cancel_booking | move_booking | create_session | message | remind | nudge | offer_time, required) - actions[].op (string, required): The operation it runs, e.g. sessions.create - actions[].input (object, required): The operation's input - actions[].facts (object, required): What it's about and why: the session or booking, the reason, the refund, the drafted words - actions[].money (boolean): It refunds - actions[].reversible (boolean): Once done, proposals_undo can reverse it - actions[].result (object) - actions[].result.ok (boolean, required) - actions[].result.data (any) - actions[].result.error (string) - actions[].undo (object) - actions[].undo.op (string, required) - actions[].undo.input (object, required) - money (boolean, required): An action refunds - reversible (boolean, required): Done, and proposals_undo can reverse it - expires_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - decided_at (string | null, required): ISO 8601 timestamp (UTC) - decided_by (string | null, required): dashboard, api, mcp or agent - done_at (string | null, required): ISO 8601 timestamp (UTC) - error (string | null, required) ### proposals_dismiss: POST /proposals/{id}/dismiss Dismiss a pending proposal; nothing runs Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - automation (weather | fill | brief | reminders, required): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - status (pending | done | failed | dismissed | expired | undone, required): pending waits for proposals_approve or proposals_dismiss; approving runs it, so it lands on done or failed - dial (ask | do_tell | do_quiet, required): ask: it waited for a person · do_tell, do_quiet: the agent acted on its own - title (string, required) - day (string, required): The local date it's for - session_id (string | null, required) - booking_id (string | null, required) - data (object, required): The brief: trips (today's sessions), unanswered threads and weather; held: "cap" or "money" when the agent waited instead of acting - actions (object[], required): Registry operations, run in order as the agent - actions[].kind (cancel_session | cancel_booking | move_booking | create_session | message | remind | nudge | offer_time, required) - actions[].op (string, required): The operation it runs, e.g. sessions.create - actions[].input (object, required): The operation's input - actions[].facts (object, required): What it's about and why: the session or booking, the reason, the refund, the drafted words - actions[].money (boolean): It refunds - actions[].reversible (boolean): Once done, proposals_undo can reverse it - actions[].result (object) - actions[].result.ok (boolean, required) - actions[].result.data (any) - actions[].result.error (string) - actions[].undo (object) - actions[].undo.op (string, required) - actions[].undo.input (object, required) - money (boolean, required): An action refunds - reversible (boolean, required): Done, and proposals_undo can reverse it - expires_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - decided_at (string | null, required): ISO 8601 timestamp (UTC) - decided_by (string | null, required): dashboard, api, mcp or agent - done_at (string | null, required): ISO 8601 timestamp (UTC) - error (string | null, required) ### proposals_undo: POST /proposals/{id}/undo Undo a done proposal that opened a session: the session is cancelled, while nobody has booked it Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - automation (weather | fill | brief | reminders, required): fill: open or fill sessions · brief: the morning brief · reminders: before and after each booking · weather: not available yet - status (pending | done | failed | dismissed | expired | undone, required): pending waits for proposals_approve or proposals_dismiss; approving runs it, so it lands on done or failed - dial (ask | do_tell | do_quiet, required): ask: it waited for a person · do_tell, do_quiet: the agent acted on its own - title (string, required) - day (string, required): The local date it's for - session_id (string | null, required) - booking_id (string | null, required) - data (object, required): The brief: trips (today's sessions), unanswered threads and weather; held: "cap" or "money" when the agent waited instead of acting - actions (object[], required): Registry operations, run in order as the agent - actions[].kind (cancel_session | cancel_booking | move_booking | create_session | message | remind | nudge | offer_time, required) - actions[].op (string, required): The operation it runs, e.g. sessions.create - actions[].input (object, required): The operation's input - actions[].facts (object, required): What it's about and why: the session or booking, the reason, the refund, the drafted words - actions[].money (boolean): It refunds - actions[].reversible (boolean): Once done, proposals_undo can reverse it - actions[].result (object) - actions[].result.ok (boolean, required) - actions[].result.data (any) - actions[].result.error (string) - actions[].undo (object) - actions[].undo.op (string, required) - actions[].undo.input (object, required) - money (boolean, required): An action refunds - reversible (boolean, required): Done, and proposals_undo can reverse it - expires_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - decided_at (string | null, required): ISO 8601 timestamp (UTC) - decided_by (string | null, required): dashboard, api, mcp or agent - done_at (string | null, required): ISO 8601 timestamp (UTC) - error (string | null, required) ## Customers ### customers_list: GET /customers List customers, newest first; q searches name, email and phone. Page with before=. Request: - q (query, string · ≤ 100 chars) - limit (query, integer · 1–500) - before (query, string · uuid): A customer's id: the page continues with those added before them (pass next_before) Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].org_id (string, required) - data[].email (string, required): Lowercase; unique within the org - data[].name (string, required) - data[].phone (string, required) - data[].notes (string, required) - data[].metadata (any, required): Free-form JSON object for your own integrations - data[].created_at (string, required): ISO 8601 timestamp (UTC) - next_before (string | null, required): Pass as before= for the next page; null after the last ### customers_get: GET /customers/{id} Get a customer with their bookings Request: - id (path, string · uuid, required) Response 200: JSON - id (string, required) - org_id (string, required) - email (string, required): Lowercase; unique within the org - name (string, required) - phone (string, required) - notes (string, required) - metadata (any, required): Free-form JSON object for your own integrations - created_at (string, required): ISO 8601 timestamp (UTC) - bookings (object[], required) - bookings[].id (string, required) - bookings[].org_id (string, required) - bookings[].offering_id (string, required) - bookings[].session_id (string | null, required): Classes only; a course's, the first time it was booked from - bookings[].series_id (string | null): A course's booking: the calendar entry it holds a seat in every time of, from session_id's on. Null for a booking of one time - bookings[].customer_id (string, required) - bookings[].starts_at (string, required): ISO 8601 timestamp (UTC) - bookings[].ends_at (string, required): ISO 8601 timestamp (UTC) - bookings[].quantity (integer, required): class: seats · appointment: people, 1 for one-on-one · rental: items - bookings[].total_cents (integer, required): In the org's currency, in the currency's minor units (cents; whole yen for zero-decimal currencies): what's left to pay after a promo code - bookings[].promo_code (string | null): The promo code it was booked with, as stored; kept after the code is deleted. Null without one - bookings[].discount_cents (integer): What the promo code took off, in the currency's minor units (cents; whole yen for zero-decimal currencies); 0 without one - bookings[].gift_card_id (string | null): The gift card that paid part of it (gift_cards_get); null without one - bookings[].gift_cents (integer): What the gift card paid, in the currency's minor units (cents; whole yen for zero-decimal currencies), counted as paid: taken off the card once the booking is confirmed, back on it if it's cancelled; 0 without one - bookings[].reference (string, required): Short code the guest sees, e.g. 0GWYRZ2V - bookings[].status (held | confirmed | cancelled, required): held, confirmed or cancelled; a hold keeps its place until expires_at - bookings[].source (string, required): Where it was made: dashboard, api, mcp, widget, octo (a reseller, over /api/octo), or assistant (held for a guest over /api/mcp/book/{slug}, who confirms it) - bookings[].notes (string, required) - bookings[].answers (object): The guest's answers to its offering's questions, keyed by question id: text (a choice's option, as listed), or true or false for a yes or no - bookings[].metadata (any, required): Free-form JSON object for your own integrations - bookings[].cancelled_at (string | null, required): ISO 8601 timestamp (UTC) - bookings[].created_at (string, required): ISO 8601 timestamp (UTC) - bookings[].expires_at (string | null, required): Held bookings: when the hold stops keeping its place - bookings[].handle (string, required): Opens the guest's own page, /b/{handle}: their messages, bookings and cancel. daybooked sends it only to the guest's email; never give it to whoever is booking, who may have typed someone else's email. bookings.resend emails it to the guest again - bookings[].checkout_url (string | null, required): Stripe Checkout for a hold being paid online - bookings[].paid_at (string | null, required): When it was paid: online, or marked paid by hand (then payment_intent_id is null) - bookings[].paid_cents (integer | null): What's been paid so far, online and by hand, in the currency's minor units (cents; whole yen for zero-decimal currencies): less than total_cents after a deposit, the rest due at the start. Null on bookings from before deposits: the whole total once paid_at is set - bookings[].payment_intent_id (string | null, required): The Stripe payment, when paid online - bookings[].charged_cents (integer | null): What its Stripe Checkout charged, a deposit or the whole total, in the currency's minor units (cents; whole yen for zero-decimal currencies): all that cancelling can refund. Null when not paid online, and on bookings from before deposits (the whole total) - bookings[].refund_id (string | null, required): The Stripe refund of a payment made online, once Stripe took it (cancelling refunds in full, unless refund_cents says otherwise) - bookings[].refund_cents (integer | null): What cancelling refunds of a payment made online, as bookings.cancel's refund chose, in the currency's minor units (cents; whole yen for zero-decimal currencies): null the whole payment, 0 none (the business kept it), otherwise that part - bookings[].refunded_at (string | null, required): When Stripe confirmed the refund; until then it's on its way - bookings[].refund_failed_at (string | null, required): When the last try at the refund failed - bookings[].refund_error (string | null, required): Why the refund failed, as Stripe said - bookings[].refund_next_at (string | null, required): When daybooked next looks at the refund (a pending one, or another try); null once refunded or failed for good - bookings[].guest_cancel_hours (integer | null): The window promised when it was booked: the guest may cancel on their page, or change its time, until this many hours before the start (or by the org's rule now, if kinder) - bookings[].nudged_at (string | null): When the guest of this lapsed, unpaid hold was emailed a link to finish booking (bookings_nudge), which goes once - bookings[].choose_by (string | null): Its time was called off with sessions_cancel and guests: "choose": it stays confirmed, holding no place, while its guest picks another time (bookings move it) or takes the refund, until the end of this day in the org's time zone. Past it, it is cancelled, refunding what was paid online. Null otherwise, and once it is cancelled - bookings[].waiver_token (string | null): When its offering asks guests to sign your waiver: the signing link for everyone on the booking, /w/{waiver_token}. It only lets someone sign - bookings[].waiver (object | null): bookings.get and bookings.list: how many signatures of your waiver it needs and has; null when its offering doesn't ask, or it's cancelled or a lapsed hold - bookings[].confirmed_at (string | null): When it was confirmed; null while held, and on bookings older than this field - bookings[].updated_at (string | null): When it last changed; null on bookings older than this field - bookings[].reseller_reference (string | null): A reseller's own reference for a booking it made over OCTO - bookings[].cancel_reason (string | null): Why a reseller cancelled it, in its words - bookings[].checked_in_at (string | null): When the guest was checked in at the door (a rental's guest: picked up), by hand on the roster or with bookings_set_attendance; null otherwise - bookings[].no_show_at (string | null): When it was marked a no-show, once its time had started; never set together with checked_in_at - bookings[].previous (object): bookings.move: where the booking was - bookings[].previous.starts_at (string, required): ISO 8601 timestamp (UTC) - bookings[].previous.ends_at (string, required): ISO 8601 timestamp (UTC) - bookings[].previous.session_id (string | null, required) - bookings[].offering (object, required) - bookings[].offering.id (string, required) - bookings[].offering.name (string, required) - bookings[].offering.kind (class | appointment | rental, required): class: sessions with seats, from its calendar · appointment: times from its calendar or weekly hours · rental: inventory over periods - bookings[].offering.questions (object[]): bookings.get and bookings.list: its questions, which answers answers by id - bookings[].offering.questions[].id (string, required): bookings.create takes the answer to this question under this id - bookings[].offering.questions[].label (string, required): The question as guests read it - bookings[].offering.questions[].type (string, required): text: a line in their words · yes_no: true or false · choice: one of its options - bookings[].offering.questions[].options (string[]): A choice's options: its answer is one of them, as listed - bookings[].offering.questions[].required (boolean, required): Guests must answer it to book online - bookings[].customer (object, required) - bookings[].customer.id (string, required) - bookings[].customer.name (string, required) - bookings[].customer.email (string, required) - bookings[].customer.phone (string, required) ### customers_upsert: POST /customers Create a customer, or update the given fields when the email already exists Request: - name (body, string · ≤ 120 chars) - phone (body, string · ≤ 40 chars) - notes (body, string · ≤ 5000 chars) - metadata (body, object) - email (body, string · email, required) Response 200: JSON - id (string, required) - org_id (string, required) - email (string, required): Lowercase; unique within the org - name (string, required) - phone (string, required) - notes (string, required) - metadata (any, required): Free-form JSON object for your own integrations - created_at (string, required): ISO 8601 timestamp (UTC) ### customers_update: PATCH /customers/{id} Update a customer's name, phone, notes or metadata Request: - id (path, string · uuid, required) - name (body, string · ≤ 120 chars) - phone (body, string · ≤ 40 chars) - notes (body, string · ≤ 5000 chars) - metadata (body, object) Response 200: JSON - id (string, required) - org_id (string, required) - email (string, required): Lowercase; unique within the org - name (string, required) - phone (string, required) - notes (string, required) - metadata (any, required): Free-form JSON object for your own integrations - created_at (string, required): ISO 8601 timestamp (UTC) ### customers_delete: DELETE /customers/{id} Erase a customer's personal data (name, email, phone, notes) on request; their bookings stay, anonymized Request: - id (path, string · uuid, required) Response 200: JSON - ok (true, required) ## Org ### org_get: GET /org Your organization: name, slug (booking page /book/{slug}), time zone, currency and how guest messages are answered Response 200: JSON - id (string, required) - name (string, required) - slug (string, required): Booking page: /book/{slug} - timezone (string, required): IANA time zone, e.g. America/Denver. Weekly hours and dates are local to it. - currency (string, required): ISO 4217 code in lowercase, e.g. usd - reply_window (string | null, required): When guests can expect a reply, e.g. "We reply by 9 AM"; part of the acknowledgement - auto_ack (boolean, required): Emails a guest who writes "Thanks, we got your message", at most once a conversation a day - away_notice (string | null, required): While set: shown on the booking page and sent with the acknowledgement - guest_cancel_hours (integer | null): Guests may cancel from their booking page until this many hours before the start, and change their time inside the same window; null: off, they write to you instead. Each booking keeps the window it was made with - review_url (string | null): Where guests leave a review; the ops agent's thank-you links it - assistant_booking (boolean): Assistants booking for a guest may hold places with no key, at /api/mcp/book/{slug}; each guest confirms by email - gift_cards (boolean): Gift cards are sold on the booking page (/book/{slug}/gift) while the business takes payments at booking - brief_hour (integer): The local hour of the ops agent's morning brief - ops_daily_cap (integer): The most the ops agent does on its own in 24 hours; past it, it asks - quiet_from (integer | null): Quiet hours start (local hour): the agent sends guests nothing on its own until quiet_to - quiet_to (integer | null): Quiet hours end (local hour) - refund_ceiling_cents (integer | null): The ops agent refunds on its own up to this; null means a refund always waits for approval - setup_site_done_at (string | null): When the go-live checklist's website step was done (the site code or booking link copied) - setup_closed_at (string | null): When the go-live checklist was closed for good; it no longer shows - created_at (string, required): ISO 8601 timestamp (UTC) ### org_update: PATCH /org Rename the organization, change its time zone (IANA, e.g. America/Denver) or currency, or set the reply window, auto-acknowledge and away notice guests see when they write Request: - name (body, string · ≤ 80 chars) - timezone (body, string · ≤ 64 chars) - currency (body, string): ISO 4217, lowercase: one Stripe charges in, not the three-decimal BHD, JOD, KWD, OMR or TND. Amounts are in its minor units (cents; whole yen for zero-decimal currencies) and aren't converted - reply_window (body, string | null): e.g. "We reply by 9 AM"; null or "" clears it - auto_ack (body, boolean): Email guests who write "Thanks, we got your message", at most once a conversation a day - away_notice (body, string | null): Shown on the booking page and sent with the acknowledgement while set; null or "" clears it - guest_cancel_hours (body, integer | null): Guests may cancel from their booking page until this many hours before the start (online payments refunded in full), and change their time inside the same window (booking.moved, source widget); null turns both off. Bookings already made keep the window they were promised - notify_new_booking (body, boolean): Email the owner each new booking made online (default true); the morning brief sums up the day either way - assistant_booking (body, boolean): Let assistants booking for a guest hold places with no key, at /api/mcp/book/{slug} (default true); the guest confirms each hold by email - gift_cards (body, boolean): Sell gift cards on the booking page, /book/{slug}/gift (default false); only while the business takes payments at booking - review_url (body, string | "" | null): Where guests leave a review (https), linked in the thank-you; null or "" clears it - brief_hour (body, integer · 0–23): The local hour of the morning brief - ops_daily_cap (body, integer · 1–500): The most the agent does on its own in 24 hours; past it, it asks - quiet_from (body, integer | null): Quiet hours start (local hour): the agent sends guests nothing on its own until quiet_to; null for none - quiet_to (body, integer | null): Quiet hours end (local hour) - refund_ceiling_cents (body, integer | null): The agent refunds on its own up to this; null means a refund always waits for approval - setup_site_done_at (body, string | null): When the go-live checklist's website step was done (the site code or booking link copied); null reopens it - setup_closed_at (body, string | null): When the go-live checklist was closed for good; null shows it again Response 200: JSON - id (string, required) - name (string, required) - slug (string, required): Booking page: /book/{slug} - timezone (string, required): IANA time zone, e.g. America/Denver. Weekly hours and dates are local to it. - currency (string, required): ISO 4217 code in lowercase, e.g. usd - reply_window (string | null, required): When guests can expect a reply, e.g. "We reply by 9 AM"; part of the acknowledgement - auto_ack (boolean, required): Emails a guest who writes "Thanks, we got your message", at most once a conversation a day - away_notice (string | null, required): While set: shown on the booking page and sent with the acknowledgement - guest_cancel_hours (integer | null): Guests may cancel from their booking page until this many hours before the start, and change their time inside the same window; null: off, they write to you instead. Each booking keeps the window it was made with - review_url (string | null): Where guests leave a review; the ops agent's thank-you links it - assistant_booking (boolean): Assistants booking for a guest may hold places with no key, at /api/mcp/book/{slug}; each guest confirms by email - gift_cards (boolean): Gift cards are sold on the booking page (/book/{slug}/gift) while the business takes payments at booking - brief_hour (integer): The local hour of the ops agent's morning brief - ops_daily_cap (integer): The most the ops agent does on its own in 24 hours; past it, it asks - quiet_from (integer | null): Quiet hours start (local hour): the agent sends guests nothing on its own until quiet_to - quiet_to (integer | null): Quiet hours end (local hour) - refund_ceiling_cents (integer | null): The ops agent refunds on its own up to this; null means a refund always waits for approval - setup_site_done_at (string | null): When the go-live checklist's website step was done (the site code or booking link copied) - setup_closed_at (string | null): When the go-live checklist was closed for good; it no longer shows - created_at (string, required): ISO 8601 timestamp (UTC) ### org_export: GET /org/export Export all your data as JSON: org, offerings, hours, sessions, customers, bookings, waivers and their signatures, waitlist entries, conversations, messages, saved replies, promo codes, gift cards and their entries, automations, proposals, webhooks and the last 1000 events Response 200: The org, offerings, hours, sessions, customers, bookings, waivers and their signatures, waitlist entries, conversations, messages, saved replies, promo codes, gift cards (each with its balance) and their entries, automations, proposals, webhooks (no secrets) and the last 1000 events ## Events ### events_list: GET /events Everything that happened, oldest first (order=desc for the newest first). Poll with after= to follow along. Request: - after (query, integer · ≥ 0) - type (query, string · ≤ 60 chars): e.g. booking.confirmed - order (query, asc | desc): desc: the newest first, for a look at what just happened; next_after is then the newest served - limit (query, integer · 1–500) Response 200: JSON - data (object[], required) - data[].id (integer, required): Increasing; poll with after= - data[].type (string, required): e.g. booking.confirmed, offering.updated - data[].data (any, required): The resource after the change: the booking, session, offering, customer or org - data[].created_at (string, required): ISO 8601 timestamp (UTC) - next_after (integer, required): Pass as after= to get what happened next ## Webhooks ### webhooks_list: GET /webhooks List webhook endpoints and their last delivery status Response 200: JSON - data (object[], required) - data[].id (string, required) - data[].url (string, required) - data[].events (string[], required): Event types it receives; ["*"] means all - data[].active (boolean, required): false once its endpoint answered 410 Gone, or the API key that made it was revoked: it gets no more events and doesn't count toward the 50 - data[].api_key_id (string | null, required): The API key that made it, whose revoking switches it off; null when no key did (the dashboard, an OAuth sign-in) - data[].last_status (integer | null, required): HTTP status of the last delivery; 0 = unreachable - data[].last_error (string | null): Why the last delivery failed, or why the webhook was switched off - data[].last_attempt_at (string | null, required): ISO 8601 timestamp (UTC) - data[].created_at (string, required): ISO 8601 timestamp (UTC) ### webhooks_create: POST /webhooks Send events to an HTTPS URL, signed with HMAC-SHA256; up to 50 per org. Returns the signing secret once. Reference: https://daybooked.io/docs/api#webhooks_create Request: - url (body, string · uri, required) - events (body, string[] · ≤ 30 items): Event types, or ["*"] for all (default) Response 201: JSON - id (string, required) - url (string, required) - events (string[], required): Event types it receives; ["*"] means all - active (boolean, required): false once its endpoint answered 410 Gone, or the API key that made it was revoked: it gets no more events and doesn't count toward the 50 - api_key_id (string | null, required): The API key that made it, whose revoking switches it off; null when no key did (the dashboard, an OAuth sign-in) - last_status (integer | null, required): HTTP status of the last delivery; 0 = unreachable - last_error (string | null): Why the last delivery failed, or why the webhook was switched off - last_attempt_at (string | null, required): ISO 8601 timestamp (UTC) - created_at (string, required): ISO 8601 timestamp (UTC) - secret (string, required): Verifies the Daybooked-Signature header. Shown once. ### webhooks_delete: DELETE /webhooks/{id} Stop sending events to a webhook endpoint Request: - id (path, string · uuid, required) Response 200: JSON - ok (true, required) ## Look ### look_get: GET /look The look of your booking page, widget and guests' booking pages: the template chosen, its colors, corners, type, tagline and logo, and the ten templates to choose from. live says whether guests see it (on any paid plan) Response 200: JSON - live (boolean, required): Guests see it: the org is on a paid plan. On Free the booking page keeps daybooked's own look - template (string | null, required): The template chosen (an id from templates); null when the org hasn't chosen one - colors (object | null, required): The page's background, its cards, its text and its accent (buttons, the chosen time), with the org's changes - corners (integer | null, required): 0 square, 50 daybooked's own, 100 as round as it goes - font (string | null, required): The type pairing chosen in place of the template's own, if any - tagline (string | null, required): A line under the business's name - show_name (boolean, required): Whether the business's name shows beside the logo - logo (object | null, required) - templates (object[], required): The ten templates, from sticker collage to dark luxury, each with its own colors and corners - templates[].id (string, required) - templates[].name (string, required) - templates[].mood (string, required): What it's like, in a few words - templates[].colors (object, required) - templates[].colors.background (string, required): Six-digit hex, e.g. #0d99ff - templates[].colors.card (string, required): Six-digit hex, e.g. #0d99ff - templates[].colors.text (string, required): Six-digit hex, e.g. #0d99ff - templates[].colors.accent (string, required): Six-digit hex, e.g. #0d99ff - templates[].corners (integer, required) ### look_update: PATCH /look Choose a template (ids from look_get) and change its colors, corners, type and tagline; guests see it at once. Pass only what changes; null puts a setting back to the template's own, and a new template resets colors, corners and font unless they're passed too. Text and accent colors are nudged if they wouldn't be readable. Paid plans only: a Free org gets 403 plan_required Request: - template (body, studio | trailhead | grid | noir | zine | scrapbook | sunset | journal | midnight | bubblegum): The template. A new one resets colors, corners and font to its own unless they're passed too - colors (body, object | null): Any of background, card, text and accent, as six-digit hex. Text and the accent are nudged if they wouldn't read - corners (body, integer | null): 0 square, 50 daybooked's own, 100 as round as it goes - font (body, clean | geometric | bold | serif | elegant | rounded | hand | mono | null): A type pairing in place of the template's own - tagline (body, string | null): A line under the business's name - show_name (body, boolean | null): Show the name beside the logo. By default a wide logo stands in for it and a square icon sits beside it - logo (body, object | null): null removes the logo. Uploading one happens in the dashboard Response 200: JSON - live (boolean, required): Guests see it: the org is on a paid plan. On Free the booking page keeps daybooked's own look - template (string | null, required): The template chosen (an id from templates); null when the org hasn't chosen one - colors (object | null, required): The page's background, its cards, its text and its accent (buttons, the chosen time), with the org's changes - corners (integer | null, required): 0 square, 50 daybooked's own, 100 as round as it goes - font (string | null, required): The type pairing chosen in place of the template's own, if any - tagline (string | null, required): A line under the business's name - show_name (boolean, required): Whether the business's name shows beside the logo - logo (object | null, required) - templates (object[], required): The ten templates, from sticker collage to dark luxury, each with its own colors and corners - templates[].id (string, required) - templates[].name (string, required) - templates[].mood (string, required): What it's like, in a few words - templates[].colors (object, required) - templates[].colors.background (string, required): Six-digit hex, e.g. #0d99ff - templates[].colors.card (string, required): Six-digit hex, e.g. #0d99ff - templates[].colors.text (string, required): Six-digit hex, e.g. #0d99ff - templates[].colors.accent (string, required): Six-digit hex, e.g. #0d99ff - templates[].corners (integer, required) ## Billing ### billing_get: GET /billing Your plan and this month's confirmed bookings against its limit (Free 25, Pro 1,000, Growth 5,000, Scale 15,000 a month). At the limit new bookings answer 402 plan_limit until the owner changes plan in the dashboard or the month turns Response 200: JSON - plan (free | pro | growth | scale, required): free, pro, growth or scale. Every paid plan adds payment at booking and the org's own look, and drops the daybooked mark - limit (integer, required): Confirmed bookings the plan takes a month - used (integer, required): Bookings made this month in the org's time zone that confirmed, cancelled since or not - pct (integer, required): used as a percentage of limit: 100 at the limit, and past it after a downgrade - paused (boolean, required): At the limit: new bookings answer 402 plan_limit until the plan changes or the month turns ## Reports ### reports_month: GET /reports/{month} A month's figures for bookings that start in the month on the org's clock: confirmed bookings going ahead, their guests and revenue_cents (what they're booked for; a cancelled booking counts nothing), no-shows and check-ins among them, live holds and cancellations; then by_offering (most revenue first, with a class's seats offered and how full they were) and by_source (where bookings came from). Counted by the database, so they hold at any volume Request: - month (path, string, required): The month, YYYY-MM, e.g. 2026-10 Response 200: JSON - month (string, required): The month, YYYY-MM, on the org's clock - from (string, required): The month's first instant, its first midnight in the org's time zone - to (string, required): The next month's first instant: the month is from up to, not including, to - currency (string, required): The org's currency, which the amounts are in (ISO 4217, lower case) - totals (object, required) - totals.bookings (integer, required): Confirmed bookings starting in the month whose time is going ahead (not one called off with its guest picking another time) - totals.guests (integer, required): Their seats, people or items: the sum of their quantity - totals.revenue_cents (integer, required): What they're booked for (their total_cents, after any promo code); a cancelled booking counts nothing, in the currency's minor units (cents; whole yen for zero-decimal currencies) - totals.no_shows (integer, required): Of those bookings, the ones marked no-show - totals.checked_in (integer, required): Of those bookings, the ones checked in (a rental's: picked up) - totals.held (integer, required): Holds starting in the month that still keep their place - totals.cancelled (integer, required): Bookings starting in the month that were cancelled - by_offering (object[], required): Each offering with bookings in the month, and each class with times in it, most revenue first - by_offering[].offering_id (string, required) - by_offering[].name (string, required) - by_offering[].kind (class | appointment | rental, required) - by_offering[].bookings (integer, required): Its confirmed bookings going ahead in the month - by_offering[].guests (integer, required): Their quantity - by_offering[].revenue_cents (integer, required): What they're booked for, in the currency's minor units (cents; whole yen for zero-decimal currencies) - by_offering[].seats_offered (integer | null, required): A class: the seats of its scheduled sessions in the month; null for the other kinds - by_offering[].fill (number | null, required): A class: guests over seats_offered, 0.68 for 68% (to 4 places); null for the other kinds - by_source (object[], required): Where the month's bookings came from, most first - by_source[].source (string, required): Where they were made: widget, dashboard, api, mcp, octo or assistant - by_source[].bookings (integer, required): Confirmed bookings going ahead