/bookings/{booking_id}/edit/* actions are the per-booking counterpart of rewriting a whole order through Editing an Existing Order.
For creating bookings, see Admin Booking Creation. For status changes, check-in, and cancellation, see Admin Booking Lifecycle. Customer self-service edits live in Customer Booking Lifecycle.
When to use which API
The admin edit actions sit next to the public
edit-* routes but under edit/ so the two surfaces do not collide. They require the admin guard, update on bookings, and read on the booking’s resource.
Prerequisites
- A valid Bearer token with admin access — see Authentication
- Organization context (
?o={organization_id}) - A confirmed booking (not
reserved) that belongs to the active organization
Shared behaviour
Every admin edit action:- Applies immediately. There is no preview /
precalculatestep and nocancel-edit-bookingcounterpart. A200means the change is persisted. - Ignores customer edit gates. Service settings such as
canEditPeriodandcanEditServiceOptionsdo not apply. Admins are not bound by the customer reschedule deadline. - Parks price corrections as an unlocked draft invoice on the order (
tmp_invoice_id). The already issued invoice is left untouched. A later edit replaces the previous draft rather than merging into it. Issue the draft explicitly when you are ready — see Invoices. - Does not run the customer pay-now flow. The customer is not sent a payment link as part of the edit.
- Rejects reserved bookings with HTTP
400andcannot_modify_reserved_booking. Carts and still-reserved orders must go through checkout, not this API.
Each call is self-contained. Walk the steps below in UI order (resource → date → fields → add-ons / sub-bookings), or call only the action you need.
Step 1 — Resource, service, and dates
Request path documentation:POST /api/v1/bookings/{booking_id}/edit/base-data
Availability is not enforced on this admin action. The booking can move onto a resource that is not wired to the booked service.
Resource scope
Duration when the service changes
Changingservice_id does update the booking duration on the backend — but through end-interval snapping, not by copying min_duration blindly:
- The requested
start_date/end_dateare resolved against the new service’s validated end intervals. - The last interval whose end is still
<=the requested end wins. If none fit (for example a 60-minute window on a 90-minute fixed service), the first interval of the new service is used. charged_durationfollows the new service’s pricing rules: a fixed-duration service stays one charged interval; a flexible service usesceil(window / calculation_interval).- Blocker padding (
blocker_start_date/blocker_end_date) comes from the new service’spadding_before/padding_after, unless you send those params to override them.
override_duration: true or an explicit duration.
Service configuration and sequences
- A single-service
service_idmap changes the booking’s service. - Adding a second service on a resource with
create_booking_sequenceturns the booking into a sequence parent:is_sequenceis true, the parent carries noservice_id, and one sequenced child is created per selected service. The parent span is snapped to the first child’s start and the last child’s end. - Dropping back to one service collapses the sequence:
is_sequenceis cleared, the remaining service is restored on the booking, and the sequenced children are removed. - Quota usage follows the children while the booking is a sequence, then returns to the parent when it collapses. Prepaid (currency) grants settle against the balance instead of charging twice.
include (for example resource.parent) to sideload the switched-to resource.
Step 2 — Fields
Customer, participants, and custom fields are separate actions. They do not go throughedit/base-data.
Reassign the customer
- When the booking is not personalized (its customer matches the order customer), the change also updates the order customer.
- When the booking is personalized, only this booking is reassigned.
- Sub-bookings and sequenced children adopt the new customer as well.
Sync participants
This is a sync of the participants you send: matching emails are updated in place. Participants missing from the payload are kept — the action never deletes attendees.
Custom fields
Booking custom fields are not on/edit/*. Load the standalone admin form, collect values, then apply them:
custom_entry_map values, deletes entries that were cleared to "" / null, and returns the booking plus a rebuilt meta.form_default. Payload shape and persistence rules are in Admin UI Forms.
You can also PATCH /api/v1/bookings/{booking_id} with custom_entry_map if you already know the field UUIDs.
Step 3 — Add-ons and sub-bookings
Request path documentation:POST /api/v1/bookings/{booking_id}/edit/service-options
Unlike the customer
edit-service-options action, an admin may attach:
- an add-on the organization owns that is not wired to the booked service
- a sub-resource / sub-service pair that is not registered as a sub-resource of the booked service
200; those rows are not written).
Quantity 0 on an add-on removes it. The replacement set is applied immediately and a correction draft is parked on the order when the issued invoice would otherwise change.
For the checkout-time add_ons_by_service / sub_bookings_by_service grouping (quantity > 1 at create time), see Add-Ons and Sub-Bookings. This admin action takes a flat list for the one booking you are editing.
Whole-order alternative
When the change is not “this one booking” but the order as a whole — extra bookings, standalone add-ons, booking passes, or removals — read the order back as a config and post the complete desired state:booking_id updates that booking; an entry without one is added; an omitted booking is soft-deleted. Sending only the bookings you changed will remove every booking you left out.
That flow, including invoice regeneration, serialization, and notify_customer rules, is documented in Editing an Existing Order.