Skip to main content
Edit a confirmed booking from the admin API, one concern at a time: resource and dates, then fields, then add-ons and sub-bookings. These /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 / precalculate step and no cancel-edit-booking counterpart. A 200 means the change is persisted.
  • Ignores customer edit gates. Service settings such as canEditPeriod and canEditServiceOptions do 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 400 and cannot_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

Changing service_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_date are 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_duration follows the new service’s pricing rules: a fixed-duration service stays one charged interval; a flexible service uses ceil(window / calculation_interval).
  • Blocker padding (blocker_start_date / blocker_end_date) comes from the new service’s padding_before / padding_after, unless you send those params to override them.
To keep a window the new service would not validate, send override_duration: true or an explicit duration.

Service configuration and sequences

  • A single-service service_id map changes the booking’s service.
  • Adding a second service on a resource with create_booking_sequence turns the booking into a sequence parent: is_sequence is true, the parent carries no service_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_sequence is 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.
The response is the refreshed Booking. Pass 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 through edit/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:
The apply endpoint persists the submitted 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
Items that belong to another organization are ignored (the request still returns 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:
A booking entry with 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.
POST /api/v1/orders/calculate always prices the config as a new order. It ignores order_id. After an edit, read meta.calculation from the from-config response, or rely on the draft correction parked by the per-booking /edit/* actions.

Common errors