Changelog
API changes, additions, and deprecations.
2026-11-05: Any Idempotency-Key works on POST /bookings
- Fix: an
Idempotency-Keythat is not a UUID (for exampleorder-123) madePOST /bookingsanswer500. Any string up to 255 characters now works, and a retry with the same key still returns the original booking.
2026-11-02: Staff with Online booking off
Additive; nothing changes for existing keys.
- A staff member whose Online booking switch is off at a location is not offered by
GET /availabilityand cannot be booked or rescheduled onto withPOST /bookingsorPOST /bookings/{id}/reschedule(technician_not_found), the same as on the business's booking page. Clients never reach them. - A key with Can book staff with Online booking off (set by the business under Developers, per key) still sees and books them, for a business's own test or front desk integrations. Everything else about the key is unchanged.
2026-10-21: Services that need several staff members
Additive; no existing field changed.
GET /servicesandGET /services/{id}returnstaff_needed(1 to 6). A couples massage is 2: one appointment, two staff members at the same time, in one room.- For such a service
GET /availabilityonly returns times when that many staff members who do it are free together, andPOST /bookingsbooks all of them (you send one booking; the business sees one booking per staff member, linked). The price is split evenly between them; the customer pays the service price once.
2026-10-20: Booking a client who has no phone
- Fix:
POST /bookingswith acontact_idfor a client who has an email but no phone number now keeps that client on the booking. Before, the booking was made without the client attached.
2026-10-20: Replaced gift cards, and what a cancel does with a deposit
Additive; no existing field changed.
- Replaced gift cards are linked. When a business replaces a lost or damaged card, the
whole balance moves to a new card.
GET /gift-cardsandGET /gift-cards/{id}now returnreplaced_by_gift_card_idon the old card (it readsvoidedat balance 0; the customer kept their money on the new card) andreplaces_gift_card_idon the new one. Both arenullotherwise. - Cancel and deposits, documented.
POST /bookings/{id}/cancelturns anything the customer already paid toward the appointment into store credit with the business, and a late-cancellation fee from the business's policy is taken from that deposit first. No card is refunded automatically.
2026-10-16: Location limits everywhere, and a currency error code
- Location-limited keys are now limited on every location record.
GET /gift-cards/{id},GET /contacts/{id}/memberships,GET /members/{id}/visitsand every webhook route now honor the key's locations (a record of another location answers404), and the documentedlocation_idfilter onGET /gift-cards,GET /packagesandGET /membershipsnow narrows the list (it must be one of the key's locations). - New error code
currency_mismatch(422,type: invalid_request): a request that would carry money or value between locations that use different currencies. Do not retry it; the message says why. Class check-in and cancel used to answer500 class_action_failedfor this case. See Errors. POST /members/resolvechecks every check-in rule (blackout window, home-location-only, the location's check-in blocks, per-member credits and the currency rule), sovalid_for_checkin: truemeans the check-in will be accepted. New optional fieldsmessageandblock_reasons.
2026-10: Built for chat and texting assistants
Additive; no existing field changed.
- Find a client's appointments:
GET /bookingstakesphoneandemail(matched the same way booking matches a contact, any stored phone format) and returnscontact_foundandmatched_contacts, each withclient_status(neworreturning). Newexclude_cancelledandorder(asc/desc) filters. - Alternatives on a taken time:
409 slot_unavailableon create and reschedule now includeserror.alternatives, up to 3 of the next open slots for the same service and staff member. A failed reschedule leaves the original untouched. - Availability: the response includes the location's
timezoneandnext_available(the earliest open slot, searched past the requested days when they have none). Newlimitparameter. Every slot carriestechnician_name.
2026-10: Scheduling fixes and new fields
Fixes (behavior now matches the public booking page):
GET /availabilityreturned slot times shifted by the location's UTC offset. Slotstart/endare now the correct instants.- "Any available": without
technician_id, at a location where every appointment needs a staff member, availability is the union across everyone who performs the service, each slot names the staff member who is free (technician_id), andPOST /bookingswithouttechnician_idassigns that person. At most 7 days per request in this mode (422 days_too_large). - Availability, create and reschedule size the visit for the staff member doing it (their own duration, waiting period and cleanup time), and create and reschedule re-check the start against working and location hours and the booking rules.
POST /bookings/{id}/cancelnow cancels exactly like the dashboard (status, notifications, calendar,booking.cancelledwebhook and automations).- Rescheduling to another staff member re-sizes the visit for that person. A
cancelled booking can no longer be rescheduled (
409 booking_cancelled). GET /services/{id}andPOST /bookingsuse the same catalog asGET /services(the location's price; deleted, inactive or not-offered services are not found). An unknownservice_idonGET /availabilityis a404instead of a 30 minute guess.- A malformed id (not a UUID) is a
422 invalid_id/invalid_field, not a500. GET /contacts?search=finds a name written with or without accents ("jose" finds "José", "pena" finds "Peña"). Contacts that match the exact spelling come first, in the same order as before; accent-only matches are listed after them.- Temporary read failures answer
503(retry) instead of a partial result.
New fields:
- Service:
wait_minutes,finish_minutes,client_stays_in_room. - Booking:
statusis now always one of the documented values, mapped from the status's meaning (new valueschecked_in,passed); the business's own name isstatus_name.staff_busylists when the staff member is actually busy.slugis documented. - Currency: every priced object (
Location,Service, gift cards, packages, membership plans) has acurrency(uppercase ISO 4217), and webhook payment events (payment.received,payment.refunded) carrydata.currencynext toamount_centsandtip_cents. Additive; no existing field changed. Never assume USD. - Webhooks: the delivery body is documented as
WebhookEvent.
Spec corrections: GET /services is not paginated (it never was), and fields the API
never returned were removed from the spec (Service.category, Location.slug,
Contact.location_id, and the location_id filter on GET /contacts).
2026-09: Classes (gyms and studios)
- Classes:
GET /classes(the timetable with booked / spots left),GET /classes/{id}(roster with what covers each spot, plus the waitlist),POST /classes/{id}/book,POST /classes/{id}/cancel,POST /classes/{id}/check-in(consumes the covering membership visit or package credit; honors the member check-in alert blocks). - New scopes:
read:classes,write:classes.
2026-09: Members and check-in
- Members:
POST /members/resolve(map a member code or fob UID to a member and check eligibility, for kiosks, turnstiles, and biometric devices),POST /members/check-in(record a facility check-in),GET /members/{id}/visits. - Memberships:
GET /contacts/{id}/memberships(what a customer holds, with status and remaining credits). - New scopes:
write:memberships,checkin:members.
2026-09: v1 launch
The first public version of the Booking Pro API:
- General:
GET /ping. - Availability:
GET /availability. - Catalog:
GET /services,GET /services/{id},GET /locations. - Contacts:
GET /contacts,GET /contacts/{id},POST /contacts,PATCH /contacts/{id}. - Bookings:
GET /bookings,GET /bookings/{id},POST /bookings,POST /bookings/{id}/cancel,POST /bookings/{id}/reschedule. - Stored value (read): gift cards, package templates, membership plans.
- Per-key API keys with scopes, cursor pagination, idempotency keys, and a published Claude Agent Skill.