Skip to main content
POST
/
v1
/
venues
/
{venue_id}
/
bookings
curl -X POST https://api.saoma.io/v1/venues/8f1a9c3b-8d4e-4f21-a1b2-c3d4e5f60718/bookings \
  -H "Authorization: Bearer $SAOMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "variant_id": "c3e4a5b6-789a-4bcd-ef01-23456789abcd",
    "start_at": "2026-05-12T12:00:00Z",
    "guest_count": 1,
    "guest": {
      "first_name": "Marie",
      "last_name": "Durand",
      "email": "marie@example.com",
      "phone": "+33612345678",
      "language": "fr"
    },
    "notes": "Préférence pression moyenne.",
    "external_reference": "staycation.ABC123",
    "external_id": "STAYCATION-ABC123",
    "price_paid": { "amount": 120.00, "currency": "EUR" }
  }'
{
  "data": {
    "id": "7f1a9c3b-8d4e-4f21-a1b2-c3d4e5f60718",
    "booking_number": 4832,
    "status": "pending",
    "start_at": "2026-05-12T12:00:00Z",
    "variant_id": "c3e4a5b6-789a-4bcd-ef01-23456789abcd",
    "guest_count": 1,
    "external_reference": "staycation.ABC123",
    "external_id": "STAYCATION-ABC123",
    "total_price": { "amount": 120.0, "currency": "EUR" }
  }
}
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.
This call is idempotent on external_id. Sending the same external_id twice for the same venue returns the original booking instead of creating a duplicate. Set it to a stable id on your side.

Path parameters

venue_id
string
required
The venue id (UUID) or slug.

Body parameters

variant_id
string
required
The bookable variant (UUID), as returned by GET /v1/venues/{venue_id}/treatments. The parent treatment and the duration are resolved from it.
start_at
string (ISO 8601 UTC)
required
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.
guest_count
integer
default:"1"
Number of guests (1–20).
guest
Guest
required
notes
string
Free-text note passed to the venue (allergies, preferences, etc.). Max 500 chars.
external_reference
string
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.
external_id
string
Your own technical reference for this request. Used as the idempotency key (unique per venue).
price_paid
Money
required
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 with status: "pending". total_price echoes the price_paid you sent. payment_method is partner_billed and payment_status is paid.

Errors

HTTPBodyMeaning
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

Example

curl -X POST https://api.saoma.io/v1/venues/8f1a9c3b-8d4e-4f21-a1b2-c3d4e5f60718/bookings \
  -H "Authorization: Bearer $SAOMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "variant_id": "c3e4a5b6-789a-4bcd-ef01-23456789abcd",
    "start_at": "2026-05-12T12:00:00Z",
    "guest_count": 1,
    "guest": {
      "first_name": "Marie",
      "last_name": "Durand",
      "email": "marie@example.com",
      "phone": "+33612345678",
      "language": "fr"
    },
    "notes": "Préférence pression moyenne.",
    "external_reference": "staycation.ABC123",
    "external_id": "STAYCATION-ABC123",
    "price_paid": { "amount": 120.00, "currency": "EUR" }
  }'
{
  "data": {
    "id": "7f1a9c3b-8d4e-4f21-a1b2-c3d4e5f60718",
    "booking_number": 4832,
    "status": "pending",
    "start_at": "2026-05-12T12:00:00Z",
    "variant_id": "c3e4a5b6-789a-4bcd-ef01-23456789abcd",
    "guest_count": 1,
    "external_reference": "staycation.ABC123",
    "external_id": "STAYCATION-ABC123",
    "total_price": { "amount": 120.0, "currency": "EUR" }
  }
}