https://api.[tenant].getomneo.com/api/v3.
Booking flow
1
List published definitions
2
Read the definition and its booking questions
3
Fetch availability for a location and date
requires_staff: true, pass staff_id, and first call available-staff to populate a staff picker. For a calendar view, use available-slots-range with start_date and end_date (capped at 31 days) instead of calling the single-day endpoint repeatedly.4
Create the appointment
instant definition the response status is confirmed. For an approval_required definition it is requested. Times are sent in timezone and stored in UTC. Pass assigned_staff_id when the definition requires staff.Availability responses
available-staff and available-slots are POST endpoints that take a location_id and date in the body and return what a booking UI needs to render pickers.
Call available-staff first when the definition has requires_staff: true, to populate a staff picker for the date:
Then call
available-slots for the chosen staff member (or without staff_id for a non-staff definition):
slots is one bookable start time for the day together with the capacity still available at that time. The array is empty when the day has no availability, so an empty slots is the normal “fully booked or closed” response, not an error. For a staff-required definition the slots belong to the staff member in the response, so fetch slots per staff member. staff is null for a non-staff definition. The meta block echoes the definition settings that shaped the calculation, so a UI can show buffers and lead time without a second read.
Use
available-slots-range with start_date and end_date (capped at 31 days) for a calendar view. It returns the same per-day shape for each date in the range instead of one day at a time.answers[], so you can confirm what was captured without a follow-up read.
The appointment resource
A create (POST), read (GET), or update (PUT) returns the appointment wrapped in a data object. This is the shape a booking against the approval_required bra-fitting definition returns, so status is requested and the confirmation timestamps are still null:
10:00 on 11 May in Australia/Melbourne becomes 2026-05-11T00:00:00Z. Convert back to local time on the client using timezone.
Fields you send
These are the fields a create or update accepts. On the profile-scoped route,profile_id is inferred from the URL.
Fields returned
The answer object
Each element ofanswers[] records one captured answer and how it was routed to its destination.
The link object
Each element oflinks[] records one additional Profile or List attached through the link endpoints, separate from the profile_id the appointment is booked for.
Reading an appointment
Read a single appointment withGET /api/v3/appointments/{id}. The response is the same resource shape shown above, with its nested profile, location, assigned_staff, answers, and links loaded.
Deleting an appointment
DELETE /api/v3/appointments/{id} removes the appointment and returns 204 with no body. To keep a record of the booking instead, set status to cancelled rather than deleting, which preserves the appointment with its cancelled_at timestamp.
Response codes
Fetching a customer’s appointments
Use the profile-scoped endpoint to list appointments for a specific profile:profile_id from the URL so you do not send it in the body:
A nested route returns
404 when the appointment id does not belong to the profile in the URL, which lets a customer-facing UI scope safely to the signed-in customer.
The global endpoint is also available and accepts a profile filter, which is useful for admin queries that combine filters across multiple profiles or need additional filtering dimensions not exposed on the profile-scoped route:
Combine filters with AND logic. For a customer’s upcoming confirmed bookings:
The list endpoint is paginated. Use
page[size] to control the page size and page through meta.pagination like every other Omneo list endpoint.Listing and filtering definitions
The Appointment Definition list supports these filters:
For example, every published definition bookable at a location:
Filtering appointments by type
The Appointment Definition is the type. To fetch every appointment of a given type, filter the appointments list by its definition rather than fetching everything and filtering on the front end:To filter the appointments list by service, use Then pass the returned
appointment_definition_id (the definition’s id). The list does not accept the definition handle as a filter, so if you only have a handle, resolve it to an id first:id as filter[appointment_definition_id].type field: its definition is its type, so filter by appointment_definition_id to group appointments of one kind.
Fetching visible definitions for a profile
When building a customer-facing booking flow, use the profile-scoped visibility endpoint to retrieve only the published, non-archived definitions that Omneo evaluates as visible for a specific Profile:read-appointment-definitions token scope. It applies each definition’s visibility_condition (a JsonLogic rule) against the Profile’s attributes and returns only those definitions where the rule evaluates to true. Definitions with a null visibility_condition are excluded.
For customer UIs where every profile should see the same published definitions, set visibility_condition to {"==": [1, 1]} on those definitions so they pass the check for all profiles.
See Visibility conditions in the Appointments concept for how the condition is evaluated.
Managing the lifecycle
Update an appointment withPUT /api/v3/appointments/{id}. Sending a status stamps the matching timestamp automatically, for example confirmed sets confirmed_at and completed sets completed_at. Omneo does not enforce a fixed transition order, so you can set any status directly: a requested booking can be cancelled or marked no_show without being confirmed first.
Booking answers are captured at creation only. To collect post-visit feedback, create a separate questionnaire and submit it through
POST /api/v3/questionnaires/{id}/submissions.
Linking records
An appointment can reference other records, for example to tie a consultation to the sale that followed. There are two mechanisms: a single Transaction or Order set on the appointment itself, and additional Profiles or Lists attached through the link endpoints.Attaching a Transaction or Order
Attach a completed Transaction or a pending Order with a resolver object on create or update. Each is a single association. You do not need the internal id: send whichever identifier you have and Omneo resolves it.null to detach:
Linking Profiles or Lists
Link one or more additional Profiles or Lists to an appointment through the dedicated link endpoint. These are separate from theprofile_id the appointment is booked for: use them for a second attendee, a stylist’s Profile, or a marketing List.
{ "type": "profile" | "list", "id": <value> }. Use a Profile UUID when type is profile, and an integer List id when type is list. Linking returns 200 and is idempotent, so linking the same record twice has no extra effect.
Unlink with the same body shape:
204 with no body.
Walk-in queues and waitlists
For definitions that allow walk-ins, check a customer into the queue withPOST /api/v3/appointment-queues. When no slot suits, register interest with POST /api/v3/appointment-waitlists and fulfil it later by creating an appointment. See Walk-in queues and waitlists for both flows, their statuses, and how to convert either into an appointment.
End-to-end example: an approval-required fitting
This walks the full lifecycle of a staff-assigned, approval-required booking, from choosing the service to attaching the sale that followed.1
Resolve the definition by handle
id (here 1) and read its booking questions to render the form: GET /api/v3/appointment-definitions/1/questions.2
Pick a staff member and a slot
has_available_slots is true, then fetch that staff member’s slots with available-slots, passing staff_id.3
Create the request
201 with status: "requested".4
Approve the request
status becomes confirmed and confirmed_at is stamped. If the definition has a confirmed_target_id, this is when its notification schedules.5
Run the appointment and tie it to the sale
completed_at is stamped and transaction resolves to the linked sale, so the booking and its outcome are recorded together.Errors
Every appointment endpoint uses the same status codes.Edge cases and gotchas
- Times are stored in UTC. You send
scheduled_start_atin the requesttimezone, but every datetime the appointment returns is UTC. Convert back on the client using the returnedtimezone, and do not assume the returned string matches what you sent. - Booking answers are captured at create only. Sending
answerson aPUTdoes not add or change them. Collect post-visit input with a separate questionnaire submitted throughPOST /api/v3/questionnaires/{id}/submissions. - Assign staff when the definition requires it. For a definition with
requires_staff: true, sendassigned_staff_id. Fetch the eligible pool fromavailable-stafffirst. - Delete is not the same as cancel.
DELETEremoves the record and returns204. Settingstatustocancelledkeeps the appointment with itscancelled_attimestamp, which is usually what you want for reporting. - Linking is idempotent. Linking the same Profile or List twice through the link endpoint has no extra effect, so a retry is safe.
- No fixed status order. Omneo stamps whatever status you set and does not enforce a path, so a
requestedbooking can go straight tocancelledorno_show.
Related
- Appointments concept
- Interactions
- Managing appointment definitions
- Walk-in queues and waitlists
- Browse appointments API
- Add appointment API
- Browse profile appointments API
- Browse visible appointment definitions API
- Browse available appointment slots API
- Browse available appointment slots over a date range API
- Submit questionnaire API
- Profile Normal Hour API
- Profile Special Hour API