Skip to main content

Appointment Booking Flows

This page covers the four booking flows supported by the Orchestra Calendar Public API, with sequence diagrams, decision guidance, and critical implementation notes. For full endpoint reference, see the Appointment Integration guide and the Calendar API reference.

Choosing a flow​

ScenarioRecommended flowAPI version
Customer picks branch first, then serviceBranch-firstv1
Customer picks service first (e.g. "I need a passport renewal")Service-firstv1 + v2 helper
High-contention slots or multi-step form after slot selectionReserve → Confirmv1 or v2
Family / group bookings, or appointment covers multiple servicesMulti-customer / multi-servicev2 only
v1 and v2 coexist

Neither version is deprecated. Use v1 for standard single-customer flows and v2 when you need multi-customer/service support or the convenience helpers (nextAvailableSlot, reserveFirstAvailable).


Flow 1 — Branch-first booking​

The most common self-service pattern. Present the customer with a branch picker first, then show services available at that branch.


Flow 2 — Service-first booking​

Use when the customer knows what they need but not which branch. The v2 GET /branches/available endpoint filters branches that can serve a given set of services — useful when not all branches offer all services.


Flow 3 — Reserve → Confirm​

Recommended for multi-step booking forms. The slot is held while the customer fills in their details. If they abandon, the hold expires and the slot returns to the pool.

Reservation timeout

The default hold period is 10 minutes. If your booking form takes longer (e.g. ID verification), call PUT /v2/branches/appointments/{publicAppointmentId}/extend before expiry. Once expired, the publicAppointmentId is no longer valid and the slot must be re-reserved.


Flow 4 — Multi-customer / multi-service (v2 only)​

For family appointments, group sessions, or slots that cover multiple services in sequence. Use the v2 book endpoint with arrays for both services and customers.

Example request body:

{
"title": "Family check-in",
"services": [
{ "servicePublicId": "abc...64chars" },
{ "servicePublicId": "def...64chars" }
],
"customers": [
{
"firstName": "Charles",
"lastName": "Ryder",
"email": "charles.ryder@example.com",
"externalId": "EXT-001"
},
{
"firstName": "Julia",
"lastName": "Flyte",
"email": "julia.flyte@example.com",
"externalId": "EXT-002"
}
]
}

Critical implementation notes​

Always use UTC timestamps

The Calendar API interprets times relative to the branch's configured time zone. If you send wall-clock times without an offset, bookings will land in the wrong slot in branches with non-UTC time zones. Always send ISO-8601 with a UTC offset — e.g. 2026-05-01T09:00:00+02:00 — or convert to UTC before sending.

Sync window blackout: 00:00–00:05 UTC

Orchestra runs a nightly synchronisation job starting at midnight UTC. Do not call write endpoints (create, update, delete) between 00:00 and 00:05 UTC. Calls during this window may fail silently or conflict with the sync. Schedule batch imports to start at 00:10 UTC or later.

Design your externalId carefully

externalId is the bridge between Orchestra's customer record and your master system. It must uniquely identify a person across all branches and sessions. A reliable formula is a combination of stable personal identifiers — email + full name + date of birth, hashed or concatenated. Avoid session IDs or order numbers that can change; externalId is used as a lookup key across all appointments.

info
Controlling notification channels with custom

The custom field on the appointment (free-form string, typically JSON-encoded) controls how Orchestra contacts the customer. Set the notify key to "email", "sms", "both", or "none". Omitting it falls back to the branch's default notification setting.

{ "custom": "{\"notify\":\"email\"}" }
v7.4 breaking change — customer object privacy

As of Orchestra v7.4, the customer object returned from public API endpoints only includes publicId. Full customer details (firstName, email, etc.) are no longer returned in public-facing responses. If you relied on reading customer data back from booking confirmation responses, switch to the internal GET /api/v1/customers/{id} endpoint instead.


Slot conflicts and retries​

The Calendar API is optimistic — it does not lock a slot when you call /times. Between fetching available times and calling /book, another caller may take the slot. If this happens, you'll receive 409 Conflict.

ResponseMeaningAction
201 CreatedBooking succeededStore publicId for confirmation emails and future operations
409 ConflictSlot was takenRefresh /times and let the customer pick again. Use reserve→confirm for high-contention slots.
404 Not FoundInvalid publicId or branch not mobile-enabledRe-fetch branches/services; confirm branch has Mobile enabled in Business Configuration.
410 Gone on confirmReservation expiredGo back to /times and start a new reserve.