API reference
The REST API lives at https://daybag.io/api/v1: send Authorization: Bearer daybag_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.
Offerings
GET/offeringsofferings_list
List offerings (classes, appointments and rentals), paused ones included
Request
- kindquery
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].org_idrequired
- string
- data[].kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- data[].namerequired
- string
- data[].descriptionrequired
- string
- data[].locationrequired
- string
- data[].duration_minutesrequired
- integer · Length of a class session or appointment, or of one rental period (1440 = a day)
- data[].capacityrequired
- integer · class: seats per session · appointment: parallel bookings per slot · rental: items in stock
- data[].max_per_bookingrequired
- integer · Most seats, party size or items in one booking
- data[].price_centsrequired
- integer · class: per seat · appointment: per booking · rental: per item per period
- data[].slot_interval_minutesrequired
- integer | null · Minutes between start times; null means back to back
- data[].buffer_minutesrequired
- integer
- data[].min_notice_minutesrequired
- integer
- data[].max_advance_daysrequired
- integer
- data[].max_periodsrequired
- integer · Rentals: the most periods one booking can span
- data[].activerequired
- boolean · false pauses booking: guests and agents can't book it, and it stays in your dashboard
- data[].metadatarequired
- any · Free-form JSON object for your own integrations
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
POST/offeringsofferings_create
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
- namerequired
- string · ≤ 120 chars
- description
- string · ≤ 2000 chars
- location
- string · ≤ 200 chars
- duration_minutes
- integer · 5–43200 · Length of a class session or appointment, or of one rental period (1440 = a day)
- capacity
- integer · 1–10000 · class: seats per session · appointment: parallel bookings per slot · rental: items in stock
- max_per_booking
- integer · 1–10000 · Most seats, party size or items in one booking
- price_cents
- integer · ≥ 0 · class: per seat · appointment: per booking · rental: per item per period
- slot_interval_minutes
- integer | null · Minutes between start times; null means back to back
- buffer_minutes
- integer · 0–1440 · Gap kept free around appointments and rentals
- min_notice_minutes
- integer · 0–43200
- max_advance_days
- integer · 1–730
- max_periods
- integer · 1–60 · Rentals: the most periods one booking can span
- active
- boolean · false pauses booking: guests and agents can't book it, and it stays in your dashboard
- metadata
- object · Free-form JSON for your own integrations
- kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
Response 201
- idrequired
- string
- org_idrequired
- string
- kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- namerequired
- string
- descriptionrequired
- string
- locationrequired
- string
- duration_minutesrequired
- integer · Length of a class session or appointment, or of one rental period (1440 = a day)
- capacityrequired
- integer · class: seats per session · appointment: parallel bookings per slot · rental: items in stock
- max_per_bookingrequired
- integer · Most seats, party size or items in one booking
- price_centsrequired
- integer · class: per seat · appointment: per booking · rental: per item per period
- slot_interval_minutesrequired
- integer | null · Minutes between start times; null means back to back
- buffer_minutesrequired
- integer
- min_notice_minutesrequired
- integer
- max_advance_daysrequired
- integer
- max_periodsrequired
- integer · Rentals: the most periods one booking can span
- activerequired
- boolean · false pauses booking: guests and agents can't book it, and it stays in your dashboard
- metadatarequired
- any · Free-form JSON object for your own integrations
- created_atrequired
- string · ISO 8601 timestamp (UTC)
GET/offerings/{id}offerings_get
Get one offering
Request
- idpathrequired
- string · uuid
Response 200
- idrequired
- string
- org_idrequired
- string
- kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- namerequired
- string
- descriptionrequired
- string
- locationrequired
- string
- duration_minutesrequired
- integer · Length of a class session or appointment, or of one rental period (1440 = a day)
- capacityrequired
- integer · class: seats per session · appointment: parallel bookings per slot · rental: items in stock
- max_per_bookingrequired
- integer · Most seats, party size or items in one booking
- price_centsrequired
- integer · class: per seat · appointment: per booking · rental: per item per period
- slot_interval_minutesrequired
- integer | null · Minutes between start times; null means back to back
- buffer_minutesrequired
- integer
- min_notice_minutesrequired
- integer
- max_advance_daysrequired
- integer
- max_periodsrequired
- integer · Rentals: the most periods one booking can span
- activerequired
- boolean · false pauses booking: guests and agents can't book it, and it stays in your dashboard
- metadatarequired
- any · Free-form JSON object for your own integrations
- created_atrequired
- string · ISO 8601 timestamp (UTC)
PATCH/offerings/{id}offerings_update
Update an offering. Set active: false to pause booking; it stays in your dashboard.
Request
- idpathrequired
- string · uuid
- name
- string · ≤ 120 chars
- description
- string · ≤ 2000 chars
- location
- string · ≤ 200 chars
- duration_minutes
- integer · 5–43200 · Length of a class session or appointment, or of one rental period (1440 = a day)
- capacity
- integer · 1–10000 · class: seats per session · appointment: parallel bookings per slot · rental: items in stock
- max_per_booking
- integer · 1–10000 · Most seats, party size or items in one booking
- price_cents
- integer · ≥ 0 · class: per seat · appointment: per booking · rental: per item per period
- slot_interval_minutes
- integer | null · Minutes between start times; null means back to back
- buffer_minutes
- integer · 0–1440 · Gap kept free around appointments and rentals
- min_notice_minutes
- integer · 0–43200
- max_advance_days
- integer · 1–730
- max_periods
- integer · 1–60 · Rentals: the most periods one booking can span
- active
- boolean · false pauses booking: guests and agents can't book it, and it stays in your dashboard
- metadata
- object · Free-form JSON for your own integrations
Response 200
- idrequired
- string
- org_idrequired
- string
- kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- namerequired
- string
- descriptionrequired
- string
- locationrequired
- string
- duration_minutesrequired
- integer · Length of a class session or appointment, or of one rental period (1440 = a day)
- capacityrequired
- integer · class: seats per session · appointment: parallel bookings per slot · rental: items in stock
- max_per_bookingrequired
- integer · Most seats, party size or items in one booking
- price_centsrequired
- integer · class: per seat · appointment: per booking · rental: per item per period
- slot_interval_minutesrequired
- integer | null · Minutes between start times; null means back to back
- buffer_minutesrequired
- integer
- min_notice_minutesrequired
- integer
- max_advance_daysrequired
- integer
- max_periodsrequired
- integer · Rentals: the most periods one booking can span
- activerequired
- boolean · false pauses booking: guests and agents can't book it, and it stays in your dashboard
- metadatarequired
- any · Free-form JSON object for your own integrations
- created_atrequired
- string · ISO 8601 timestamp (UTC)
DELETE/offerings/{id}offerings_delete
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 }.
Request
- idpathrequired
- string · uuid
- cancel_bookingsquery
- boolean · Required when the offering has upcoming bookings or live holds; otherwise the delete answers 409 with what it would cancel
Response 200
- cancelledrequired
- integer · Upcoming bookings and holds cancelled
- refundedrequired
- integer · Of those, paid online and refunded in full
GET/offerings/{id}/hoursofferings_get_hours
Weekly opening hours of an appointment or rental, in the org's local time
Request
- idpathrequired
- string · uuid
Response 200
- datarequired
- object[]
- data[].weekdayrequired
- integer · 0 = Sunday … 6 = Saturday
- data[].start_timerequired
- string · Local wall-clock time, HH:MM:SS
- data[].end_timerequired
- string · Local wall-clock time, HH:MM:SS
PUT/offerings/{id}/hoursofferings_set_hours
Replace weekly opening hours, e.g. [{ weekday: 6, start_time: '08:00', end_time: '16:00' }]
Request
- idpathrequired
- string · uuid
- hoursrequired
- object[] · ≤ 50 items
- hours[].weekdayrequired
- integer · 0–6 · 0 = Sunday … 6 = Saturday
- hours[].start_timerequired
- string
- hours[].end_timerequired
- string
Response 200
- datarequired
- object[]
- data[].weekdayrequired
- integer · 0 = Sunday … 6 = Saturday
- data[].start_timerequired
- string · Local wall-clock time, HH:MM:SS
- data[].end_timerequired
- string · Local wall-clock time, HH:MM:SS
Availability
GET/offerings/{id}/availabilityavailability_get
Bookable slots with remaining capacity between two local dates (default: the next 14 days)
Request
- idpathrequired
- string · uuid
- fromquery
- string · date · Local calendar date (YYYY-MM-DD) in the org's time zone
- toquery
- string · date · Local calendar date (YYYY-MM-DD) in the org's time zone
Response 200
- timezonerequired
- string · The org's time zone; from and to are local dates in it
- datarequired
- object[]
- data[].starts_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].ends_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].capacityrequired
- integer
- data[].remainingrequired
- integer · What's left to book: seats, parallel slots or items
- data[].session_id
- string · Classes only: pass it to bookings_create
Sessions
GET/sessionssessions_list
List class sessions with the number of seats booked
Request
- offering_idquery
- string · uuid
- fromquery
- string · ISO 8601 instant, e.g. 2026-10-03T15:00:00Z
- toquery
- string · ISO 8601 instant, e.g. 2026-10-03T15:00:00Z
- statusquery
- scheduled | cancelled
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].org_idrequired
- string
- data[].offering_idrequired
- string
- data[].starts_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].ends_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].capacityrequired
- integer | null · Seats for this session; null means the class's capacity
- data[].statusrequired
- scheduled | cancelled
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].bookedrequired
- integer · Seats booked
POST/sessionssessions_create
Schedule a class session; repeat_weeks repeats it weekly at the same local time
Request
- offering_idrequired
- string · uuid
- starts_atrequired
- string · ISO 8601 instant, e.g. 2026-10-03T15:00:00Z
- repeat_weeks
- integer · 1–52
- capacity
- integer | null · Override the class's seats
Response 201
- datarequired
- object[]
- data[].idrequired
- string
- data[].org_idrequired
- string
- data[].offering_idrequired
- string
- data[].starts_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].ends_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].capacityrequired
- integer | null · Seats for this session; null means the class's capacity
- data[].statusrequired
- scheduled | cancelled
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
POST/sessions/{id}/cancelsessions_cancel
Cancel a class session and every booking in it
Request
- idpathrequired
- string · uuid
Response 200
- idrequired
- string
- org_idrequired
- string
- offering_idrequired
- string
- starts_atrequired
- string · ISO 8601 timestamp (UTC)
- ends_atrequired
- string · ISO 8601 timestamp (UTC)
- capacityrequired
- integer | null · Seats for this session; null means the class's capacity
- statusrequired
- scheduled | cancelled
- created_atrequired
- string · ISO 8601 timestamp (UTC)
Bookings
GET/bookingsbookings_list
List bookings filtered by time range, status, offering, customer or session (order=desc for newest first)
Request
- fromquery
- string · ISO 8601 instant, e.g. 2026-10-03T15:00:00Z
- toquery
- string · ISO 8601 instant, e.g. 2026-10-03T15:00:00Z
- statusquery
- held | confirmed | cancelled
- offering_idquery
- string · uuid
- customer_idquery
- string · uuid
- session_idquery
- string · uuid
- orderquery
- asc | desc
- limitquery
- integer · 1–500
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].org_idrequired
- string
- data[].offering_idrequired
- string
- data[].session_idrequired
- string | null · Classes only
- data[].customer_idrequired
- string
- data[].starts_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].ends_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].quantityrequired
- integer · class: seats · appointment: party size · rental: items
- data[].total_centsrequired
- integer · In the org's currency
- data[].referencerequired
- string · Short code the guest sees, e.g. 0GWYRZ2V
- data[].statusrequired
- held | confirmed | cancelled · held, confirmed or cancelled; a hold keeps its place until expires_at
- data[].sourcerequired
- string · Where it was made: dashboard, api, mcp or widget
- data[].notesrequired
- string
- data[].metadatarequired
- any · Free-form JSON object for your own integrations
- data[].cancelled_atrequired
- string | null · ISO 8601 timestamp (UTC)
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].expires_atrequired
- string | null · Held bookings: when the hold stops keeping its place
- data[].handlerequired
- string · The guest's own page for the booking: /b/{handle}
- data[].checkout_urlrequired
- string | null · Stripe Checkout for a hold being paid online
- data[].paid_atrequired
- string | null · When it was paid online
- data[].payment_intent_idrequired
- string | null · The Stripe payment, when paid online
- data[].previous
- object · bookings.move: where the booking was
- data[].previous.starts_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].previous.ends_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].previous.session_idrequired
- string | null
- data[].offeringrequired
- object
- data[].offering.idrequired
- string
- data[].offering.namerequired
- string
- data[].offering.kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- data[].customerrequired
- object
- data[].customer.idrequired
- string
- data[].customer.namerequired
- string
- data[].customer.emailrequired
- string
- data[].customer.phonerequired
- string
GET/bookings/{id}bookings_get
Get one booking with its offering and customer
Request
- idpathrequired
- string · uuid
Response 200
- idrequired
- string
- org_idrequired
- string
- offering_idrequired
- string
- session_idrequired
- string | null · Classes only
- customer_idrequired
- string
- starts_atrequired
- string · ISO 8601 timestamp (UTC)
- ends_atrequired
- string · ISO 8601 timestamp (UTC)
- quantityrequired
- integer · class: seats · appointment: party size · rental: items
- total_centsrequired
- integer · In the org's currency
- referencerequired
- string · Short code the guest sees, e.g. 0GWYRZ2V
- statusrequired
- held | confirmed | cancelled · held, confirmed or cancelled; a hold keeps its place until expires_at
- sourcerequired
- string · Where it was made: dashboard, api, mcp or widget
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- cancelled_atrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- expires_atrequired
- string | null · Held bookings: when the hold stops keeping its place
- handlerequired
- string · The guest's own page for the booking: /b/{handle}
- checkout_urlrequired
- string | null · Stripe Checkout for a hold being paid online
- paid_atrequired
- string | null · When it was paid online
- payment_intent_idrequired
- string | null · The Stripe payment, when paid online
- previous
- object · bookings.move: where the booking was
- previous.starts_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.ends_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.session_idrequired
- string | null
- offeringrequired
- object
- offering.idrequired
- string
- offering.namerequired
- string
- offering.kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- customerrequired
- object
- customer.idrequired
- string
- customer.namerequired
- string
- customer.emailrequired
- string
- customer.phonerequired
- string
POST/bookingsbookings_create
Book a slot from availability.get (classes need session_id; appointments and rentals need starts_at). Pass hold_minutes to hold it instead, and idempotency_key so retries never book twice.
Request
- offering_idrequired
- string · uuid
- session_id
- string · uuid
- starts_at
- string · ISO 8601 instant, e.g. 2026-10-03T15:00:00Z
- quantity
- integer · 1–10000 · class: seats · appointment: party size · rental: items
- periods
- integer · 1–60 · Rentals: how many periods (e.g. days)
- customer_id
- string · uuid
- customer
- object · Matched by email; created if new
- customer.emailrequired
- string · email
- customer.name
- string · ≤ 120 chars
- customer.phone
- string · ≤ 40 chars
- notes
- string · ≤ 2000 chars
- hold_minutes
- integer · 5–1440 · Hold the place this many minutes (status held) instead of confirming; then call bookings.confirm
- idempotency_key
- string · uuid · A UUID you generate per booking: retrying with it returns the same booking instead of booking twice
Response 201
- idrequired
- string
- org_idrequired
- string
- offering_idrequired
- string
- session_idrequired
- string | null · Classes only
- customer_idrequired
- string
- starts_atrequired
- string · ISO 8601 timestamp (UTC)
- ends_atrequired
- string · ISO 8601 timestamp (UTC)
- quantityrequired
- integer · class: seats · appointment: party size · rental: items
- total_centsrequired
- integer · In the org's currency
- referencerequired
- string · Short code the guest sees, e.g. 0GWYRZ2V
- statusrequired
- held | confirmed | cancelled · held, confirmed or cancelled; a hold keeps its place until expires_at
- sourcerequired
- string · Where it was made: dashboard, api, mcp or widget
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- cancelled_atrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- expires_atrequired
- string | null · Held bookings: when the hold stops keeping its place
- handlerequired
- string · The guest's own page for the booking: /b/{handle}
- checkout_urlrequired
- string | null · Stripe Checkout for a hold being paid online
- paid_atrequired
- string | null · When it was paid online
- payment_intent_idrequired
- string | null · The Stripe payment, when paid online
- previous
- object · bookings.move: where the booking was
- previous.starts_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.ends_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.session_idrequired
- string | null
- offeringrequired
- object
- offering.idrequired
- string
- offering.namerequired
- string
- offering.kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- customerrequired
- object
- customer.idrequired
- string
- customer.namerequired
- string
- customer.emailrequired
- string
- customer.phonerequired
- string
POST/bookings/{id}/cancelbookings_cancel
Cancel a booking or a hold and free its capacity (safe to repeat)
Request
- idpathrequired
- string · uuid
Response 200
- idrequired
- string
- org_idrequired
- string
- offering_idrequired
- string
- session_idrequired
- string | null · Classes only
- customer_idrequired
- string
- starts_atrequired
- string · ISO 8601 timestamp (UTC)
- ends_atrequired
- string · ISO 8601 timestamp (UTC)
- quantityrequired
- integer · class: seats · appointment: party size · rental: items
- total_centsrequired
- integer · In the org's currency
- referencerequired
- string · Short code the guest sees, e.g. 0GWYRZ2V
- statusrequired
- held | confirmed | cancelled · held, confirmed or cancelled; a hold keeps its place until expires_at
- sourcerequired
- string · Where it was made: dashboard, api, mcp or widget
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- cancelled_atrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- expires_atrequired
- string | null · Held bookings: when the hold stops keeping its place
- handlerequired
- string · The guest's own page for the booking: /b/{handle}
- checkout_urlrequired
- string | null · Stripe Checkout for a hold being paid online
- paid_atrequired
- string | null · When it was paid online
- payment_intent_idrequired
- string | null · The Stripe payment, when paid online
- previous
- object · bookings.move: where the booking was
- previous.starts_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.ends_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.session_idrequired
- string | null
- offeringrequired
- object
- offering.idrequired
- string
- offering.namerequired
- string
- offering.kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- customerrequired
- object
- customer.idrequired
- string
- customer.namerequired
- string
- customer.emailrequired
- string
- customer.phonerequired
- string
POST/bookings/{id}/confirmbookings_confirm
Confirm a held booking (safe to repeat). A hold past its expires_at confirms only if its place is still free.
Request
- idpathrequired
- string · uuid
Response 200
- idrequired
- string
- org_idrequired
- string
- offering_idrequired
- string
- session_idrequired
- string | null · Classes only
- customer_idrequired
- string
- starts_atrequired
- string · ISO 8601 timestamp (UTC)
- ends_atrequired
- string · ISO 8601 timestamp (UTC)
- quantityrequired
- integer · class: seats · appointment: party size · rental: items
- total_centsrequired
- integer · In the org's currency
- referencerequired
- string · Short code the guest sees, e.g. 0GWYRZ2V
- statusrequired
- held | confirmed | cancelled · held, confirmed or cancelled; a hold keeps its place until expires_at
- sourcerequired
- string · Where it was made: dashboard, api, mcp or widget
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- cancelled_atrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- expires_atrequired
- string | null · Held bookings: when the hold stops keeping its place
- handlerequired
- string · The guest's own page for the booking: /b/{handle}
- checkout_urlrequired
- string | null · Stripe Checkout for a hold being paid online
- paid_atrequired
- string | null · When it was paid online
- payment_intent_idrequired
- string | null · The Stripe payment, when paid online
- previous
- object · bookings.move: where the booking was
- previous.starts_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.ends_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.session_idrequired
- string | null
- offeringrequired
- object
- offering.idrequired
- string
- offering.namerequired
- string
- offering.kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- customerrequired
- object
- customer.idrequired
- string
- customer.namerequired
- string
- customer.emailrequired
- string
- customer.phonerequired
- string
POST/bookings/{id}/movebookings_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
- idpathrequired
- string · uuid
- session_id
- string · uuid · Classes: the session to move to
- starts_at
- string · Appointments and rentals: the new start; the booking keeps its length
Response 200
- idrequired
- string
- org_idrequired
- string
- offering_idrequired
- string
- session_idrequired
- string | null · Classes only
- customer_idrequired
- string
- starts_atrequired
- string · ISO 8601 timestamp (UTC)
- ends_atrequired
- string · ISO 8601 timestamp (UTC)
- quantityrequired
- integer · class: seats · appointment: party size · rental: items
- total_centsrequired
- integer · In the org's currency
- referencerequired
- string · Short code the guest sees, e.g. 0GWYRZ2V
- statusrequired
- held | confirmed | cancelled · held, confirmed or cancelled; a hold keeps its place until expires_at
- sourcerequired
- string · Where it was made: dashboard, api, mcp or widget
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- cancelled_atrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- expires_atrequired
- string | null · Held bookings: when the hold stops keeping its place
- handlerequired
- string · The guest's own page for the booking: /b/{handle}
- checkout_urlrequired
- string | null · Stripe Checkout for a hold being paid online
- paid_atrequired
- string | null · When it was paid online
- payment_intent_idrequired
- string | null · The Stripe payment, when paid online
- previous
- object · bookings.move: where the booking was
- previous.starts_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.ends_atrequired
- string · ISO 8601 timestamp (UTC)
- previous.session_idrequired
- string | null
- offeringrequired
- object
- offering.idrequired
- string
- offering.namerequired
- string
- offering.kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- customerrequired
- object
- customer.idrequired
- string
- customer.namerequired
- string
- customer.emailrequired
- string
- customer.phonerequired
- string
POST/bookings/{id}/resendbookings_resend
Email the guest their booking confirmation again, at most once a day; not for held or cancelled bookings
Request
- idpathrequired
- string · uuid
Response 200
- okrequired
- true
Conversations
GET/conversationsconversations_list
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
- statusquery
- open | done
- unreadquery
- boolean
- qquery
- string · ≤ 200 chars · Matches the guest's name or email, or words in the messages
- customer_idquery
- string · uuid
- limitquery
- integer · 1–500
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].statusrequired
- open | done
- data[].last_message_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].outfitter_read_atrequired
- string | null · ISO 8601 timestamp (UTC)
- data[].guest_read_atrequired
- string | null · ISO 8601 timestamp (UTC)
- data[].snoozed_untilrequired
- string | null · ISO 8601 timestamp (UTC)
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].unreadrequired
- boolean · A guest message is newer than outfitter_read_at
- data[].needs_replyrequired
- boolean · The guest wrote last
- data[].customerrequired
- object | null · Null on a pre-sale question
- data[].last_messagerequired
- object | null
- data[].bookingrequired
- object | null · The guest's next upcoming booking, else their latest
GET/conversations/{id}conversations_get
Get a conversation with its thread oldest first: messages, notes, and the guest's booking events as system rows
Request
- idpathrequired
- string · uuid
Response 200
- idrequired
- string
- statusrequired
- open | done
- last_message_atrequired
- string · ISO 8601 timestamp (UTC)
- outfitter_read_atrequired
- string | null · ISO 8601 timestamp (UTC)
- guest_read_atrequired
- string | null · ISO 8601 timestamp (UTC)
- snoozed_untilrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- unreadrequired
- boolean · A guest message is newer than outfitter_read_at
- needs_replyrequired
- boolean · The guest wrote last
- customerrequired
- object | null · Null on a pre-sale question
- last_messagerequired
- object | null
- bookingrequired
- object | null · The guest's next upcoming booking, else their latest
- threadrequired
- object | object[]
PATCH/conversations/{id}conversations_update
Mark a conversation done or open again; read: true once the guest's messages have been seen
Request
- idpathrequired
- string · uuid
- status
- open | done
- read
- boolean
Response 200
- idrequired
- string
- statusrequired
- open | done
- last_message_atrequired
- string · ISO 8601 timestamp (UTC)
- outfitter_read_atrequired
- string | null · ISO 8601 timestamp (UTC)
- guest_read_atrequired
- string | null · ISO 8601 timestamp (UTC)
- snoozed_untilrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- unreadrequired
- boolean · A guest message is newer than outfitter_read_at
- needs_replyrequired
- boolean · The guest wrote last
- customerrequired
- object | null · Null on a pre-sale question
- last_messagerequired
- object | null
- bookingrequired
- object | null · The guest's next upcoming booking, else their latest
Messages
GET/messagesmessages_list
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_idquery
- string · uuid
- booking_idquery
- string · uuid
- customer_idquery
- string · uuid
- limitquery
- integer · 1–500
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].org_idrequired
- string
- data[].conversation_idrequired
- string | null
- data[].booking_idrequired
- string | null · The booking it's about, shown as its chip; null when about the guest in general
- data[].customer_idrequired
- string | null · Null on a pre-sale question
- data[].directionrequired
- to_guest | to_outfitter · to_guest: the outfitter wrote · to_outfitter: the guest wrote from their booking page or replied by email
- data[].subjectrequired
- string · Empty on guest messages
- data[].bodyrequired
- string
- data[].sent_byrequired
- dashboard | api | mcp | guest
- data[].channelrequired
- string · How it travelled: page (typed in daybag), email, api or system
- data[].kindrequired
- message | note · A note is the outfitter's own, never sent to the guest
- data[].read_atrequired
- string | null · When the other side read it
- data[].attachmentsrequired
- object[] · Files on it, each opened at /api/attachments/{id}
- data[].attachments[].idrequired
- string
- data[].attachments[].namerequired
- string
- data[].attachments[].sizerequired
- integer
- data[].attachments[].typerequired
- string
- data[].delivered_atrequired
- string | null · Messages to guests: when the guest's mail server took the email
- data[].failed_atrequired
- string | null · Messages to guests: when the email bounced or was marked as spam
- data[].from_namerequired
- string | null · Guest messages: the name they gave
- data[].from_emailrequired
- string | null · Guest messages: the email they gave, where replies go
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].bookingrequired
- object | null
POST/messagesmessages_send
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 outfitter. kind note keeps an internal note instead
Request
- conversation_id
- string · uuid
- booking_id
- string · uuid · The booking it's about; it shows as the message's chip
- customer_id
- string · uuid
- subject
- string · ≤ 200 chars
- bodyrequired
- string · ≤ 5000 chars
- kind
- message | note · note: for the outfitter's team, never sent
- attachments
- 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[].idrequired
- string
- attachments[].namerequired
- string · ≤ 1000 chars
Response 201
- idrequired
- string
- org_idrequired
- string
- conversation_idrequired
- string | null
- booking_idrequired
- string | null · The booking it's about, shown as its chip; null when about the guest in general
- customer_idrequired
- string | null · Null on a pre-sale question
- directionrequired
- to_guest | to_outfitter · to_guest: the outfitter wrote · to_outfitter: the guest wrote from their booking page or replied by email
- subjectrequired
- string · Empty on guest messages
- bodyrequired
- string
- sent_byrequired
- dashboard | api | mcp | guest
- channelrequired
- string · How it travelled: page (typed in daybag), email, api or system
- kindrequired
- message | note · A note is the outfitter's own, never sent to the guest
- read_atrequired
- string | null · When the other side read it
- attachmentsrequired
- object[] · Files on it, each opened at /api/attachments/{id}
- attachments[].idrequired
- string
- attachments[].namerequired
- string
- attachments[].sizerequired
- integer
- attachments[].typerequired
- string
- delivered_atrequired
- string | null · Messages to guests: when the guest's mail server took the email
- failed_atrequired
- string | null · Messages to guests: when the email bounced or was marked as spam
- from_namerequired
- string | null · Guest messages: the name they gave
- from_emailrequired
- string | null · Guest messages: the email they gave, where replies go
- created_atrequired
- string · ISO 8601 timestamp (UTC)
POST/messages/broadcastmessages_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 (target.offering_id). Returns how many were sent, skipped (erased guests) and failed
Request
- targetrequired
- object | object | object · { session_id }, { date } or { offering_id }
- subject
- string · ≤ 200 chars
- bodyrequired
- string · ≤ 5000 chars
Response 200
- sentrequired
- integer
- skippedrequired
- integer
- failedrequired
- integer
POST/messages/draftmessages_draft
Draft a reply in a conversation for the outfitter 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_idrequired
- string · uuid · The conversation to draft a reply in
Response 200
- textrequired
- string · The drafted reply, plain text, to review and edit before sending
Saved replies
GET/saved_repliessaved_replies_list
List the outfitter'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_idquery
- string · uuid · Fill the replies in for this booking and its guest
- conversation_idquery
- string · uuid · Or for this conversation's guest and their booking under way or next
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].org_idrequired
- string
- data[].titlerequired
- string · What the outfitter picks it by
- data[].bodyrequired
- string · The message as saved, with its {variables}
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].updated_atrequired
- string · ISO 8601 timestamp (UTC)
- data[].textrequired
- string · The body filled in for booking_id or conversation_id, ready for messages_send; without them only {org} is filled in
POST/saved_repliessaved_replies_create
Save a reply the outfitter 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
Request
- titlerequired
- string · ≤ 80 chars · What it's picked by, such as Directions
- bodyrequired
- 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 201
- idrequired
- string
- org_idrequired
- string
- titlerequired
- string · What the outfitter picks it by
- bodyrequired
- string · The message as saved, with its {variables}
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- updated_atrequired
- string · ISO 8601 timestamp (UTC)
PATCH/saved_replies/{id}saved_replies_update
Change a saved reply's title or body
Request
- idpathrequired
- string · uuid
- title
- string · ≤ 80 chars · What it's picked by, such as Directions
- 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
- idrequired
- string
- org_idrequired
- string
- titlerequired
- string · What the outfitter picks it by
- bodyrequired
- string · The message as saved, with its {variables}
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- updated_atrequired
- string · ISO 8601 timestamp (UTC)
DELETE/saved_replies/{id}saved_replies_delete
Delete a saved reply
Request
- idpathrequired
- string · uuid
Response 200
- okrequired
- true
Customers
GET/customerscustomers_list
List customers, newest first; q searches name, email and phone
Request
- qquery
- string · ≤ 100 chars
- limitquery
- integer · 1–500
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].org_idrequired
- string
- data[].emailrequired
- string · Lowercase; unique within the org
- data[].namerequired
- string
- data[].phonerequired
- string
- data[].notesrequired
- string
- data[].metadatarequired
- any · Free-form JSON object for your own integrations
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
GET/customers/{id}customers_get
Get a customer with their bookings
Request
- idpathrequired
- string · uuid
Response 200
- idrequired
- string
- org_idrequired
- string
- emailrequired
- string · Lowercase; unique within the org
- namerequired
- string
- phonerequired
- string
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- bookingsrequired
- object[]
- bookings[].idrequired
- string
- bookings[].org_idrequired
- string
- bookings[].offering_idrequired
- string
- bookings[].session_idrequired
- string | null · Classes only
- bookings[].customer_idrequired
- string
- bookings[].starts_atrequired
- string · ISO 8601 timestamp (UTC)
- bookings[].ends_atrequired
- string · ISO 8601 timestamp (UTC)
- bookings[].quantityrequired
- integer · class: seats · appointment: party size · rental: items
- bookings[].total_centsrequired
- integer · In the org's currency
- bookings[].referencerequired
- string · Short code the guest sees, e.g. 0GWYRZ2V
- bookings[].statusrequired
- held | confirmed | cancelled · held, confirmed or cancelled; a hold keeps its place until expires_at
- bookings[].sourcerequired
- string · Where it was made: dashboard, api, mcp or widget
- bookings[].notesrequired
- string
- bookings[].metadatarequired
- any · Free-form JSON object for your own integrations
- bookings[].cancelled_atrequired
- string | null · ISO 8601 timestamp (UTC)
- bookings[].created_atrequired
- string · ISO 8601 timestamp (UTC)
- bookings[].expires_atrequired
- string | null · Held bookings: when the hold stops keeping its place
- bookings[].handlerequired
- string · The guest's own page for the booking: /b/{handle}
- bookings[].checkout_urlrequired
- string | null · Stripe Checkout for a hold being paid online
- bookings[].paid_atrequired
- string | null · When it was paid online
- bookings[].payment_intent_idrequired
- string | null · The Stripe payment, when paid online
- bookings[].previous
- object · bookings.move: where the booking was
- bookings[].previous.starts_atrequired
- string · ISO 8601 timestamp (UTC)
- bookings[].previous.ends_atrequired
- string · ISO 8601 timestamp (UTC)
- bookings[].previous.session_idrequired
- string | null
- bookings[].offeringrequired
- object
- bookings[].offering.idrequired
- string
- bookings[].offering.namerequired
- string
- bookings[].offering.kindrequired
- class | appointment | rental · class: scheduled sessions with seats · appointment: slots from weekly hours · rental: inventory over periods
- bookings[].customerrequired
- object
- bookings[].customer.idrequired
- string
- bookings[].customer.namerequired
- string
- bookings[].customer.emailrequired
- string
- bookings[].customer.phonerequired
- string
POST/customerscustomers_upsert
Create a customer, or update the given fields when the email already exists
Request
- name
- string · ≤ 120 chars
- phone
- string · ≤ 40 chars
- notes
- string · ≤ 5000 chars
- metadata
- object
- emailrequired
- string · email
Response 200
- idrequired
- string
- org_idrequired
- string
- emailrequired
- string · Lowercase; unique within the org
- namerequired
- string
- phonerequired
- string
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- created_atrequired
- string · ISO 8601 timestamp (UTC)
PATCH/customers/{id}customers_update
Update a customer's name, phone, notes or metadata
Request
- idpathrequired
- string · uuid
- name
- string · ≤ 120 chars
- phone
- string · ≤ 40 chars
- notes
- string · ≤ 5000 chars
- metadata
- object
Response 200
- idrequired
- string
- org_idrequired
- string
- emailrequired
- string · Lowercase; unique within the org
- namerequired
- string
- phonerequired
- string
- notesrequired
- string
- metadatarequired
- any · Free-form JSON object for your own integrations
- created_atrequired
- string · ISO 8601 timestamp (UTC)
DELETE/customers/{id}customers_delete
Erase a customer's personal data (name, email, phone, notes) on request; their bookings stay, anonymized
Request
- idpathrequired
- string · uuid
Response 200
- okrequired
- true
Org
GET/orgorg_get
Your organization: name, slug (booking page /book/{slug}), time zone, currency and how guest messages are answered
Response 200
- idrequired
- string
- namerequired
- string
- slugrequired
- string · Booking page: /book/{slug}
- timezonerequired
- string · IANA time zone, e.g. America/Denver. Weekly hours and dates are local to it.
- currencyrequired
- string · ISO 4217 code in lowercase, e.g. usd
- reply_windowrequired
- string | null · When guests can expect a reply, e.g. "We reply by 9 AM"; part of the acknowledgement
- auto_ackrequired
- boolean · Emails a guest who writes "Thanks, we got your message", at most once a conversation a day
- away_noticerequired
- string | null · While set: shown on the booking page and sent with the acknowledgement
- created_atrequired
- string · ISO 8601 timestamp (UTC)
PATCH/orgorg_update
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
- string · ≤ 80 chars
- timezone
- string · ≤ 64 chars
- currency
- string
- reply_window
- string | null · e.g. "We reply by 9 AM"; null or "" clears it
- auto_ack
- boolean · Email guests who write "Thanks, we got your message", at most once a conversation a day
- away_notice
- string | null · Shown on the booking page and sent with the acknowledgement while set; null or "" clears it
Response 200
- idrequired
- string
- namerequired
- string
- slugrequired
- string · Booking page: /book/{slug}
- timezonerequired
- string · IANA time zone, e.g. America/Denver. Weekly hours and dates are local to it.
- currencyrequired
- string · ISO 4217 code in lowercase, e.g. usd
- reply_windowrequired
- string | null · When guests can expect a reply, e.g. "We reply by 9 AM"; part of the acknowledgement
- auto_ackrequired
- boolean · Emails a guest who writes "Thanks, we got your message", at most once a conversation a day
- away_noticerequired
- string | null · While set: shown on the booking page and sent with the acknowledgement
- created_atrequired
- string · ISO 8601 timestamp (UTC)
GET/org/exportorg_export
Export all your data as JSON: org, offerings, hours, sessions, customers, bookings, conversations, messages, saved replies, webhooks and the last 1000 events
Response 200The org, offerings, hours, sessions, customers, bookings, conversations, messages, saved replies, webhooks (no secrets) and the last 1000 events
Events
GET/eventsevents_list
Everything that happened, oldest first. Poll with after=<next_after> to follow along.
Request
- afterquery
- integer · ≥ 0
- typequery
- string · ≤ 60 chars · e.g. booking.confirmed
- limitquery
- integer · 1–500
Response 200
- datarequired
- object[]
- data[].idrequired
- integer · Increasing; poll with after=<id>
- data[].typerequired
- string · e.g. booking.confirmed, offering.updated
- data[].datarequired
- any · The resource after the change: the booking, session, offering, customer or org
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
- next_afterrequired
- integer · Pass as after= to get what happened next
Webhooks
GET/webhookswebhooks_list
List webhook endpoints and their last delivery status
Response 200
- datarequired
- object[]
- data[].idrequired
- string
- data[].urlrequired
- string
- data[].eventsrequired
- string[] · Event types it receives; ["*"] means all
- data[].activerequired
- boolean
- data[].last_statusrequired
- integer | null · HTTP status of the last delivery; 0 = unreachable
- data[].last_attempt_atrequired
- string | null · ISO 8601 timestamp (UTC)
- data[].created_atrequired
- string · ISO 8601 timestamp (UTC)
POST/webhookswebhooks_create
Send events to an HTTPS URL, signed with HMAC-SHA256. Returns the signing secret once.
Request
- urlrequired
- string · uri
- events
- string[] · ≤ 30 items · Event types, or ["*"] for all (default)
Response 201
- idrequired
- string
- urlrequired
- string
- eventsrequired
- string[] · Event types it receives; ["*"] means all
- activerequired
- boolean
- last_statusrequired
- integer | null · HTTP status of the last delivery; 0 = unreachable
- last_attempt_atrequired
- string | null · ISO 8601 timestamp (UTC)
- created_atrequired
- string · ISO 8601 timestamp (UTC)
- secretrequired
- string · Verifies the Daybag-Signature header. Shown once.
DELETE/webhooks/{id}webhooks_delete
Stop sending events to a webhook endpoint
Request
- idpathrequired
- string · uuid
Response 200
- okrequired
- true
Billing
GET/billingbilling_get
Your plan (free or pro) and this month's confirmed bookings against the free plan's soft cap of 25
Response 200
- planrequired
- free | pro · pro: payment at booking, no daybag mark, no booking cap
- usagerequired
- object
- usage.usedrequired
- integer · Confirmed bookings created this UTC month
- usage.caprequired
- integer · The free plan's soft cap. Bookings keep confirming past it.
- usage.pctrequired
- integer · used as a percentage of cap; keeps climbing past 100