Bookings
Create a booking
Push a new booking into a venue’s agenda.
POST
Creates a booking at a specific slot. Saoma atomically reserves a treatment
room; if the slot is still available, the booking is created as
pending and
broadcast to the venue’s therapists. Requires the bookings:write scope.
The booking is not confirmed synchronously. It is created as
pending
and confirmed once a therapist accepts the broadcast. Confirmation will be
delivered via webhooks (coming soon); until then, the partner is responsible
for tracking the outcome.Path parameters
The venue id (UUID) or slug.
Body parameters
The bookable variant (UUID), as returned by
GET /v1/venues/{venue_id}/treatments. The parent treatment and the duration
are resolved from it.Start time of the slot, as an absolute instant. Converted to the venue’s
local time using the venue timezone. Must be in the future.
Number of guests (1–20).
Free-text note passed to the venue (allergies, preferences, etc.). Max 500
chars.
Provenance of the booking, formatted
source.XXXX (e.g.
staycation.ABC123). The prefix before the . is lower-cased and, when it
matches a known type (staycation, classpass, hotel), stored as the
booking’s client_type; otherwise client_type is external.Your own technical reference for this request. Used as the idempotency
key (unique per venue).
Amount you charged the customer, in major units (e.g.
120.00 for €120).
Stored as the booking’s authoritative total_price — it is trusted as-is and
may differ from Saoma’s own price. { amount: number, currency: "EUR" }. The
currency must match the venue currency.Response
Returns the created booking withstatus: "pending". total_price echoes the
price_paid you sent. payment_method is partner_billed and payment_status
is paid.
Errors
| HTTP | Body | Meaning |
|---|---|---|
| 400 | { "error": "…" } | Missing or malformed fields |
| 403 | { "error": "Insufficient scope" } | Key lacks bookings:write |
| 403 | { "error": "Forbidden" } | Venue belongs to another organization |
| 404 | { "error": "Variant not found" } | Unknown variant, or not bookable for this venue |
| 409 | { "error": "slot_unavailable" } | Slot is no longer available (retry another slot) |
| 409 | { "error": "duplicate_external_id" } | Concurrent request with the same external_id |
| 422 | { "error": "price_paid.currency must … " } | price_paid.currency ≠ venue currency |