Order & Checkout Flow (Public)
Create bookings through the public cart and checkout flow. For admin-side creation (orders/from-config), see Admin Booking Creation.
For conventions, see JSON-API Conventions. For slot search, see Availability & Booking Search.
Prerequisites
- Resource + service configuration exists
- Cookies are enabled (cart and order authorization are cookie/query based)
- Optional customer auth for prefilled fields
Canonical Path Docs
/api/v1/order*cart/checkout endpoints: ../../paths/public/orders.yaml
Flow Overview
1. Add booking(s) to cart
2. Show recommendations in cart
3. Edit cart / voucher
4. Collect checkout data
5. Optional guest email verification
6. Submit checkout
7. Handle payment redirect
8. Fetch last succeeded orders
Step 1 — Add Booking to Cart
POST /api/v1/order/bookings
{
"resource_id": "{resource_id}",
"service_id": {
"{service_id}": 1
},
"start_date": "2026-04-15T09:00:00+02:00",
"end_date": "2026-04-15T10:00:00+02:00",
"add_ons_by_service": {
"{service_id}": [
[
{ "add_on_id": "{add_on_id}", "quantity": 2 }
]
]
},
"sub_bookings_by_service": {
"{service_id}": [
[]
]
}
}
add_ons_by_service and sub_bookings_by_service are mapped by service id and booking index:
| Field | Type | Notes |
|---|---|---|
service_id |
string | object |
Object map (service_id -> quantity) is current format |
add_ons_by_service |
object |
{service_id: AddOn[][]} |
add_ons_by_service[service_id][booking_index][] |
array item | {add_on_id, quantity} |
sub_bookings_by_service |
object |
{service_id: SubBooking[][]} |
Legacy inputs (booking_add_ons, sub_bookings) still exist but are deprecated.
Exact add-booking request fields (current request rules):
| Field | Type | Required | Notes |
|---|---|---|---|
start_date |
string (atom date-time) | yes | |
end_date |
string (atom date-time) | yes | >= start_date |
service_id |
string | int | object | yes | object map recommended (service_id -> quantity) |
resource_id |
string | int | array | yes | can be multi-resource |
description |
string | no | nullable |
customer_note |
string | no | nullable |
add_ons_by_service |
object | no | nullable |
sub_bookings_by_service |
object | no | nullable |
recurring |
object | no | nullable |
recurring.frequency |
enum | no | daily, weekly, monthly |
recurring.duration |
int | conditional | required when end_date not used by recurring flow |
recurring.until |
date | no | nullable |
recurring.interval |
int | no | |
recurring.days |
array | no | |
recurring.month_day |
int | no | |
recurring.week_start |
string | no | |
recurring.set_pos |
int | no | |
strategy |
enum | no | availability booking strategy |
timezone |
IANA timezone | no | |
create_sequence |
boolean | no | |
timeslot_series_id |
int | no | |
original_booking_id |
string | no | |
book_on_behalf |
string | no | customer account uuid |
account_pass |
string | no | pass code |
booking_quota_grant_id |
string | int | array | no | |
prevent_applying_default_quota |
boolean | no | |
adhoc |
boolean | no |
Path docs: /api/v1/order/bookings in ../../paths/public/orders.yaml.
Current cart:
GET /api/v1/order
Step 2 — Recommendations in Cart (Before Checkout)
Recommendations are a cart-time feature, not a post-order step.
GET /api/v1/order/recommendations
Step 3 — Edit Cart and Voucher
Edit add-ons for one booking:
POST /api/v1/order/bookings/{booking_id}/edit-addons
{
"addons": [
{ "add_on_id": "{add_on_id}", "quantity": 1 }
]
}
Remove one booking:
DELETE /api/v1/order/bookings/{booking_id}
Remove multiple bookings:
DELETE /api/v1/order/bookings/delete-multiple
{
"filter": {
"id": ["{booking_id_1}", "{booking_id_2}"]
}
}
Clear cart:
GET /api/v1/order/bookings/delete-all
Apply voucher:
POST /api/v1/order/voucher
{
"code": "SUMMER20"
}
Remove voucher:
DELETE /api/v1/order/voucher
Optional booking pre-calculation:
POST /api/v1/order/bookings/calculate
Step 4 — Collect Checkout Data
Collect the customer data, payment method, and legal document acceptances required for the current organization.
Public integrations should treat these requirements as organization-defined checkout configuration rather than depending on internal UI helper endpoints.
Step 5 — Optional Guest Email Verification
If guest email verification is enabled for the checkout flow, complete that verification before the final order submission.
The external contract is the verify_guest_email field on POST /api/v1/order. Helper endpoints used by anny-hosted UIs are internal-only and not part of the external integration surface.
Step 6 — Submit Checkout
POST /api/v1/order
{
"customer": {
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe"
},
"payment_method": "{payment_method_slug}",
"documents": {
"{legal_doc_uuid}": true
},
"verify_guest_email": {
"state": "{email_verification_state}",
"code": "123456"
}
}
Validation depends on the organization's checkout configuration and selected payment method.
Step 7 — Handle Payment Redirect
If meta.payment.next_action.type = redirect, redirect to meta.payment.next_action.url.
After the payment provider redirects the user back, proceed to Step 8 to fetch the completed order.
Step 8 — Fetch Last Succeeded Orders
last-succeeded authorization is token-pair based and requires matching oids[] and oats[] arrays.
GET /api/v1/order/last-succeeded?oids[]={order_id_1}&oats[]={access_token_1}&oids[]={order_id_2}&oats[]={access_token_2}
Common Errors
| Error | Cause | Solution |
|---|---|---|
422 add-ons ignored or invalid |
Wrong add_ons_by_service shape |
Use service_id -> booking_index -> [{add_on_id, quantity}] |
422 slot unavailable |
Race condition between selection and checkout | Re-check availability and re-add booking |
409 order already completed |
Duplicate checkout submit | Block duplicate submit and refresh cart state |
422 verification code invalid |
Wrong/expired guest email code | Request a new code |