Booking Flow

Baskets

A Basket is the mutable, in-progress cart that a customer (or an integration acting on their behalf) builds before checkout — items, guests, discounts, payment methods and the paying customer all attach here. Totals on the basket are tentative; no money has moved.

Submitting (actionSubmitBasket) runs the booking-engine validation suite — availability, reservation policies, practitioner / room / area constraints, deposits, intake-form requirements — and only on success creates the Order, reserves the bookings, and captures payment. Use Baskets for any customer-driven purchase.

Post-submit reads and edits (refunds, cancellations, additional payments) go through Orders. See Basket vs Order in the basket-and-checkout guide for the full contrast.

The Basket object

Attributes

{
  "id": "64a9f3b2c3d8e1f4a5b6c7d8",
  "applied_promo_code": {
    "id": "64a9f3b2c3d8e1f4a5b6c7d8",
    "applied_at": "2023-11-15T12:00:00+00:00",
    "applied_by": {},
    "code": "FIVEOFF",
    "discount_total": 2000,
    "is_discount_applied": true,
    "percentage": 10
  },
  "applied_promo_code_discount_total": 1,
  "applied_promo_code_id": "00000000-0000-0000-0000-000000000000",
  "coupon_codes": [
    {
      "id": "64a9f3b2c3d8e1f4a5b6c7d8",
      "code": "FIVEOFF",
      "name": "April special",
      "description": "Get 10% off all treatments booked in April.",
      "customer_credit_id": "00000000-0000-0000-0000-000000000000"
    }
  ],
  "currency": "GBP",
  "customer_id": "00000000-0000-0000-0000-000000000000",
  "discount_total": 1,
  "email": "guest@example.com",
  "guests": [
    "string"
  ],
  "first_name": "Alex",
  "is_promo_code_discount_applied": true,
  "items": [
    {
      "id": "64a9f3b2c3d8e1f4a5b6c7d8",
      "currency": "GBP",
      "date": "2026-01-15",
      "discounts": [
        "string"
      ],
      "duration": 1,
      "guest": "string",
      "guests": [
        "string"
      ],
      "image": "string",
      "item_configuration": {},
      "net_total": 1,
      "offering_categories": [
        {
          "id": "64a9f3b2c3d8e1f4a5b6c7d8",
          "name": "Alex Morgan"
        }
      ],
      "offering_id": "64a9f3b2c3d8e1f4a5b6c7d8",
      "offering_name": "string",
      "offering_type": "string",
      "option_budgets": [
        {
          "budget": "string",
          "choice_id": "00000000-0000-0000-0000-000000000000",
          "remaining": "string",
          "spent": "string"
        }
      ],
      "package_items": [
        {
          "id": "64a9f3b2c3d8e1f4a5b6c7d8",
          "booking_summary": "string",
          "choice_id": "64a9f3b2c3d8e1f4a5b6c7d8",
          "duration": 1,
          "guests": [
            "string"
          ],
          "item_configuration": "string",
          "offering_id": "64a9f3b2c3d8e1f4a5b6c7d8",
          "offering_name": "60 minute massage",
          "offering_type": "appointment",
          "option_id": "64a9f3b2c3d8e1f4a5b6c7d8",
          "price_change": 1500,
          "reserved_until": "2026-01-15T09:30:00+00:00",
          "shared_basket_item_id": "64a9f3b2c3d8e1f4a5b6c7d8",
          "status": "string",
          "time": "2026-01-15T09:30:00+00:00"
        }
      ],
      "price": 1,
      "purchasable_details": {
        "delivery_date": "2026-01-15T09:30:00+00:00"
      },
      "quantity": 1,
      "reserved_until": "2026-01-15T09:30:00+00:00",
      "tax_amount": 1,
      "tax_percent": 1,
      "time": "2026-01-15T09:30:00+00:00",
      "total_cost": 1,
      "validity": {
        "errors": [
          {
            "message": "string"
          }
        ],
        "valid": false
      },
      "will_be_waitlisted": false
    }
  ],
  "items_reserved_until": "2026-01-15T09:30:00+00:00",
  "last_name": "Morgan",
  "net_total": 1,
  "order_ref": "EXT-12345",
  "organisation_id": "00000000-0000-0000-0000-000000000000",
  "outstanding_payment_amount": 1,
  "payments": [
    "string"
  ],
  "phone": "+447700900000",
  "promo_code_applied_at": "2026-01-15T09:30:00+00:00",
  "promo_code_applied_by": {
    "id": "64a9f3b2c3d8e1f4a5b6c7d8",
    "avatar": "string",
    "email": "guest@example.com",
    "first_name": "Jane",
    "full_name": "Jane Smith",
    "last_name": "Smith"
  },
  "site_id": "00000000-0000-0000-0000-000000000000",
  "special_requests": "string",
  "status": "submitted",
  "submit_auth_amount": 1,
  "submit_errors": [
    {
      "error": "string",
      "message": "string",
      "time": 1
    }
  ],
  "submit_payment_amount": 1,
  "submitted_at": "2026-01-15T09:30:00+00:00",
  "total_cost": 1,
  "total_paid_or_authed": 1,
  "total_tax": 1,
  "totals": {
    "applied_vouchers": 1,
    "auth_required": 1,
    "discounts": 1,
    "gross_total": 1,
    "net_total": 1,
    "payment_required": 1,
    "tax": 1
  },
  "voucher_codes": [
    {
      "id": "00000000-0000-0000-0000-000000000000",
      "amount_type": "discount_to_zero",
      "calculated_amount": 1000,
      "code": "ABCDEFGHIJ123",
      "coupon_code_id": "64a9f3b2c3d8e1f4a5b6c7d8",
      "description": "A 30 minute treatment of your choice.",
      "is_redeemed": true,
      "name": "30 min treatment",
      "voucher_type_id": "64a9f3b2c3d8e1f4a5b6c7d8"
    }
  ],
  "created_at": "string",
  "updated_at": "string"
}
post/shop/basket/{basketId}/items

Add an item to a Basket

createBasketItem

Use this endpoint to add an item to a Basket.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • discount_amountintegeroptionalnullable

    Manual discount to apply to this line item, in the smallest currency unit (e.g. pence, cents). Subtracted from the line subtotal before tax. Defaults to 0 / null (no discount).

  • guest_idsstring[]optional
  • guestsobject[]optional
  • offering_idobject-idoptional

    ID of the offering being added to the basket. Required for every offering_type other than free-form vouchers. The format depends on the offering type — practitioner-scheduled offerings use Mongo ObjectIDs.

  • offering_typestringrequired

    Discriminator describing what kind of sellable item an Offering represents. The value determines which downstream schema (Appointment, Session, Package, etc.) the offering's offering_id resolves against, and which checkout/booking flow applies.

    Possible values:appointmentappointment_enquiryarea_bookingcoursehotel_room_reservationmembershippackageproductsessiontable_reservationvoucher
  • priceintegeroptional

    Override price for this line item in the smallest currency unit (e.g. pence, cents). Omit to let the server compute the price from the offering's current price rules.

  • quantityintegeroptional

    Number of units to add to the basket. Defaults to 1.

Responses

  • 200

    Successfully added an item to a Basket.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

post/shop/basket

Create a Basket

createBasket

Creates a new Basket at a Site. The basket is the central object in Trybe's checkout flow — it accumulates items (appointments, area bookings, products, vouchers, memberships, etc.), customer details, coupons, vouchers, and payments before being submitted to create an Order.

If the request is authenticated as a Customer (e.g. via a customer access token), that customer is linked to the basket automatically. Otherwise pass customer_id to associate an existing customer, or omit it and call POST /shop/basket/{basketId}/customer later in the flow.

A "Website" SalesChannel is provisioned for the site's organisation on first use and reused thereafter.

Request body

  • site_iduuidrequired

    ID of the Site the basket belongs to. The site determines currency, tax configuration, payment processors, and which offerings are bookable.

  • customer_iduuidoptional

    Optionally pre-link an existing Customer to the basket. Ignored unless the customer belongs to the same brand as the site. If the request is authenticated as a customer, the authenticated customer takes precedence.

Responses

  • 200

    The newly created Basket.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 422

    The request didn't pass validation

get/shop/basket/{basketId}

Retrieve a Basket

getBasket

Returns the full state of a Basket — its items, guests, payments, applied coupons and vouchers, totals, and submit state. This is the canonical endpoint frontends call after any mutating action to reconcile their local view of the cart.

Baskets that were submitted more than an hour ago and aren't attached to a visit return 404 so that completed checkouts can't be re-rendered by stale links.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Responses

  • 200

    The requested Basket.

  • 401

    The user is unauthenticated

  • 404

    The resource couldn't be found

put/shop/basket/{basketId}

Update a Basket

updateBasket

Updates a small set of basket-level metadata. Use this to record special requests captured during checkout (e.g. dietary requirements, accessibility notes).

Returns 400 Bad Request if the basket has already been submitted or otherwise locked.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • special_requestsstringoptional

    Free-text notes captured against the basket during checkout. Surfaced to operations staff alongside the resulting Order.

Responses

  • 200

    The updated Basket.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

get/shop/basket/{basketId}/checkout-config

Get Basket checkout configuration

getBasketCheckoutConfig

Returns the legal and clinical pre-flight data a shop frontend needs to render the final checkout step:

  • terms — the booking terms & conditions the customer must accept, assembled from site, offering, and basket-level sources.
  • contraindications — clinical contraindications attached to any appointment offerings in the basket (filtered to entries the customer must positively confirm).
  • voucher_payment_enabled — whether external voucher redemption is configured for the basket's site.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Responses

  • 200

    The checkout configuration for the basket.

  • 401

    The user is unauthenticated

  • 404

    The resource couldn't be found

post/shop/basket/{basketId}/coupons

Apply a coupon to a Basket

createBasketCoupon

Validates and applies a CouponCode to the basket. Coupons can grant percentage or fixed-amount discounts, automatic free items, or unlock pricing tiers — the basket totals are recalculated on success.

Customer-facing flows can only add coupons while the basket is in_progress. Staff (authenticated as a User) bypass that restriction provided they have the reservations.manage permission for the site.

Returns 400 Bad Request with a human-readable reason when the coupon is invalid, expired, fully redeemed, or incompatible with the basket's items.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • codestringrequired

    The customer-visible coupon code to redeem. Matched case-insensitively against issued CouponCode records for the basket's site.

Responses

  • 200

    The updated Basket with the coupon applied.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

delete/shop/basket/{basketId}/coupons/{coupon}

Remove a coupon from a Basket

deleteBasketCoupon

Detaches a previously-applied CouponCode from the basket. Any discount the coupon was contributing is reversed and the totals are recalculated.

As with POST /shop/basket/{basketId}/coupons, customer-facing flows can only remove coupons while the basket is in_progress; staff (authenticated as a User) need the reservations.manage permission for the site.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • couponobject-idrequired

    The unique identifier of the CouponCode to remove from the basket.

Responses

  • 204

    The coupon was successfully removed from the basket.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

post/shop/basket/{basketId}/customer

Set the customer on a Basket

actionSetBasketCustomer

Attaches a Customer to the basket so the resulting Order is correctly attributed and surfaced in the customer's history. There are three modes:

  1. Authenticated customer — the request is authenticated as a Customer for the basket's brand. The authenticated customer is linked directly. If they don't have a phone number on file, supply one with phone (and optionally phone_country).
  2. Existing customer by email — pass email, first_name, last_name, and optionally phone. If a customer with that email already exists for the brand they are linked; otherwise a new Customer is created using these details.
  3. Guest checkout — the same payload as mode 2 is used; the newly-created customer is linked to the basket and saved against any marketing preferences supplied.

Phone numbers are normalised to E.164 using phone_country (or the site's country code) as the default region.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • emailstringoptional

    Customer email address. Required for guest checkout. Used to look up existing customers within the site's brand before creating a new record.

  • first_namestringoptional

    Customer's given name. Required for guest checkout.

  • last_namestringoptional

    Customer's family name. Required for guest checkout.

  • phonestringoptionalnullable

    Customer's phone number. Required when the authenticated customer doesn't already have one on file; optional otherwise. Accepted in any format parseable against phone_country or the site's country code; persisted as E.164.

  • phone_countrystringoptionalnullable

    Two-letter ISO country code used to interpret an unprefixed phone. Defaults to the site's country code when omitted.

  • marketing_preferencesstring[]optional

    IDs of marketing preferences the customer has opted in to. Only honoured when creating a brand-new customer.

Responses

  • 200

    The updated Basket with the customer attached.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

post/shop/basket/{basketId}/customer-credits

Apply a customer credit to a Basket

createBasketCustomerCredit

Applies one of the customer's outstanding CustomerCredit balances against the basket. Customer credits are issued by operators as compensation, refunds-to-store-credit, or loyalty rewards; once applied to a basket they reduce the outstanding payment amount immediately.

Returns 400 Bad Request if the credit can't be redeemed — for example because it's been fully spent, has expired, or doesn't belong to the basket's customer.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • idobject-idrequired

    ID of the CustomerCredit to redeem against the basket. Must belong to the customer attached to the basket and have a remaining balance.

Responses

  • 200

    The updated Basket with the customer credit applied.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

delete/shop/basket/{basketId}/customer-credits/{customerCredit}

Remove a customer credit from a Basket

deleteBasketCustomerCredit

Detaches a previously-applied CustomerCredit from the basket. The credit's balance is restored to the customer and the basket's outstanding payment amount is recalculated.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • customerCreditobject-idrequired

    The unique identifier of the CustomerCredit to remove from the basket.

Responses

  • 204

    The customer credit was successfully removed from the basket.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

put/shop/basket/{basketId}/items/{item}

Update a Basket item

updateBasketItem

Updates the schedule and/or quantity of an existing BasketItem. Passing quantity: 0 removes the item from the basket — useful for quantity steppers in cart UIs.

The item_configuration field accepts an arbitrary object of offering-specific options (e.g. session_id for a fitness session, room_id for a treatment, flavour for a product). Availability is re-checked on every update; if the new date/time isn't bookable the response is 400 Bad Request.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • itemobject-idrequired

    The unique identifier of the BasketItem.

Request body

  • datedateoptionalnullable

    Booking date for the item. Required for scheduled offerings (appointments, area bookings, sessions).

  • timestringoptional

    Booking start time for the item, formatted as HH:mm. For ranged bookings such as area bookings, pair with end_time or duration to express the slot.

  • start_timestringoptional

    Alternative start time for ranged bookings. Formatted as HH:mm.

  • end_timestringoptional

    End time for ranged bookings. Formatted as HH:mm.

  • durationintegeroptionalnullable

    Booking duration in minutes. Must be greater than zero when supplied; allowed durations are constrained by the offering's settings.

  • quantityintegeroptional

    Number of units of this item. Must be greater than zero. Setting quantity to 0 removes the line from the basket instead of updating it.

  • item_configurationobjectoptionalnullable

    Offering-specific configuration for this line. The accepted keys depend on the offering_type — for example practitioner_id, room_id, session_id, option selections, or product variants. Unknown keys are ignored.

Responses

  • 200

    The updated Basket.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

delete/shop/basket/{basketId}/items/{item}

Remove an item from a Basket

deleteBasketItem

Removes a BasketItem from the basket. Any package items, guest assignments, and option budgets attached to the line are discarded. Reserved availability for the item is released immediately.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • itemobject-idrequired

    The unique identifier of the BasketItem.

Responses

  • 200

    The updated Basket with the item removed.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

post/shop/basket/{basketId}/items/{item}/package-items

Add a package item to a Basket item

createBasketPackageItem

Adds a child item to a package line item. Packages bundle several offerings together (e.g. a "Spa Day" comprising a treatment, lunch, and pool access). The choice_id selects which slot within the package is being filled and option_id selects which offering fills it.

For scheduled package slots, pass item_configuration with time, duration, and (where relevant) session_id so the underlying availability check has the data it needs. Top-level time and duration parameters are accepted as a legacy alternative and will be merged into the configuration server-side.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • itemobject-idrequired

    The unique identifier of the BasketItem.

Request body

  • choice_idstringrequired

    ID of the choice within the parent package that this child item is filling. Each Package defines a list of choices (e.g. "Main treatment", "Lunch", "Add-on") and the customer picks one option_id for each.

  • option_idstringrequired

    ID of the offering option fulfilling the choice. Must be one of the options defined against choice_id.

  • item_configurationobjectoptional

    Slot-specific configuration. Common keys include time (HH:mm), duration (minutes), and session_id. Unknown keys are ignored.

  • guest_idsstring[]optional

    IDs of the guests this package item applies to. When omitted the item applies to the same guests as its parent basket item.

  • timestringoptionalDeprecated

    Legacy alternative to item_configuration.time. Prefer passing the value inside item_configuration.

  • durationintegeroptionalDeprecated

    Legacy alternative to item_configuration.duration. Prefer passing the value inside item_configuration.

Responses

  • 200

    The updated Basket including the new package item.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

put/shop/basket/{basketId}/items/{item}/package-items/{packageItem}

Update a Basket package item

updateBasketPackageItem

Updates the choice/option selection or schedule of a package's child item. Useful when a customer changes their mind about which treatment to take in a "Choose your own" package slot, or needs to shift the slot's start time.

Availability is re-checked on every update.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • itemobject-idrequired

    The unique identifier of the BasketItem.

  • packageItemobject-idrequired

    The unique identifier of the BasketPackageItem.

Request body

  • choice_idstringrequired

    ID of the package choice this child item fulfils.

  • option_idstringrequired

    ID of the offering option selected for the choice.

  • timestringoptional

    New start time for the slot, formatted as HH:mm.

  • durationintegeroptional

    New duration of the slot in minutes.

Responses

  • 200

    The updated Basket.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

delete/shop/basket/{basketId}/items/{item}/package-items/{packageItem}

Remove a Basket package item

deleteBasketPackageItem

Removes a child item from a package line. Any subsequent package items that depended on this slot (e.g. a follow-on treatment scheduled relative to it) may be removed too.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • itemobject-idrequired

    The unique identifier of the BasketItem.

  • packageItemobject-idrequired

    The unique identifier of the BasketPackageItem.

Responses

  • 200

    The updated Basket with the package item removed.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

post/shop/basket/{basketId}/payments

Add a payment to a Basket

createBasketPayment

Attaches a payment intent or completed payment to the basket. Most commonly used to register a voucher or external-voucher payment alongside (or instead of) a card payment.

Behaviour depends on processor:

  • voucher / external_voucher — redeems the supplied voucher against the basket immediately. The amount defaults to the outstanding submit amount when omitted; supplying a smaller amount lets a customer split-pay across multiple methods.
  • stripe — accepted for compatibility but treated as a no-op: Stripe payments are added automatically after the customer returns from the Stripe Checkout flow.

Returns 400 Bad Request when the amount exceeds what's outstanding, when the chosen processor is misconfigured, or when the payment can't be created (e.g. voucher already spent).

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • processorstringrequired

    The payment processor handling this payment. voucher and external_voucher redeem a voucher held on the basket; stripe is accepted as a no-op for clients that still POST after a Stripe Checkout redirect.

    Possible values:voucherexternal_voucherstripe
  • amountintegeroptional

    Amount to charge against this payment, in the smallest currency unit (e.g. pence, cents). Defaults to the basket's outstanding submit amount when omitted. Must not exceed the outstanding amount.

  • voucher_codestringoptional

    For voucher processors, the voucher code to redeem. Required when processor is voucher or external_voucher and the voucher hasn't already been attached via POST /shop/basket/{basketId}/vouchers.

  • notesstringoptional

    Optional free-text note recorded against the Payment.

Responses

  • 200

    The updated Basket with the new payment attached.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

delete/shop/basket/{basketId}/payments/{payment}

Remove a payment from a Basket

deleteBasketPayment

Detaches a Payment from the basket. Any voucher balance the payment was consuming is released back to the voucher, and the basket's outstanding submit amount is recalculated.

Only valid while the basket is updatable — submitted baskets return 400 Bad Request.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • paymentobject-idrequired

    The unique identifier of the Payment to remove from the basket.

Responses

  • 200

    The updated Basket with the payment removed.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

post/shop/basket/{basketId}/pre-submit

Pre-submit validation for a Basket

actionPreSubmitBasket

Runs the same validation suite that POST /shop/basket/{basketId}/submit runs — checking availability, customer details, payment requirements, and integration pre-conditions — without committing the basket. The response is the latest basket payload, with any validation failures surfaced via the submit_errors collection.

Call this immediately before the customer enters payment details so you can fail fast and avoid taking money for a basket that's going to be rejected on submit.

Returns 400 Bad Request if the basket can't even reach the payment step (e.g. an item is unavailable or a payment processor error occurred during pre-flight).

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Responses

  • 200

    The basket after pre-submit validation has run.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

post/shop/basket/{basketId}/reserve

Reserve Basket items

actionReserveBasket

Soft-holds availability for every item in the basket so the customer can complete payment without losing their slot. Reserved items expire after a short window (the response's items_reserved_until indicates the deadline) and are automatically released if the basket isn't submitted in time.

A customer must be attached to the basket (POST /shop/basket/{basketId}/customer) before items can be reserved — call this immediately before sending the customer to the payment step.

Returns 400 Bad Request if one or more items have become unavailable since they were added; the response message identifies the conflict.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Responses

  • 200

    The updated Basket with reservations in place.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

post/shop/basket/{basketId}/submit

Submit a Basket

actionSubmitBasket

Finalises the basket and turns it into an Order. On success the basket transitions to submitted, an Order is created, appointments and area bookings are confirmed (or queued as enquiries depending on configuration), payments are captured or authorised, and confirmation email + SMS are sent to the customer.

The endpoint is idempotent within a one-hour window for already submitted baskets — a re-submit returns the existing basket with the intake-form URL attached. Beyond the window, submitted baskets respond 404 Not Found.

You can optionally include customer_id or email (and the other guest-checkout fields) directly in the submit payload to set the customer in the same request — this delegates to the same logic as POST /shop/basket/{basketId}/customer.

Returns 400 Bad Request for any submit-time failure: unavailable items, validation errors, payment failures, or a lock timeout when another concurrent submit is in progress.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • customer_iduuidoptional

    Existing Customer to attach to the basket before submitting.

  • emailstringoptional

    Email address for guest checkout.

  • first_namestringoptional

    Customer's given name for guest checkout.

  • last_namestringoptional

    Customer's family name for guest checkout.

  • phonestringoptional

    Customer's phone number. Persisted as E.164 using phone_country (or the site's country code) as the default region.

  • phone_countrystringoptional

    Two-letter ISO country code used to interpret an unprefixed phone.

  • marketing_preferencesstring[]optional

    IDs of marketing preferences the customer is opting in to. Only honoured when creating a new customer.

Responses

  • 200

    The submitted Basket (with an attached intake-form URL when relevant).

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

post/shop/basket/{basketId}/update-guests

Bulk update Basket guests

actionBulkUpdateBasketGuests

Replaces or upserts the basket's guest list in one call. Each entry can carry an id to update an existing guest in-place, or omit id to create a new guest. Pre-existing guests not referenced in the payload are left untouched.

Use this after collecting guest details on a multi-guest booking journey — it's cheaper than issuing one mutation per guest and keeps the basket's totals consistent.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • guestsobject[]optional

    The set of guests to upsert against the basket. Each entry may identify an existing guest by id (in which case the remaining fields patch the record) or omit id to create a new guest.

Responses

  • 200

    The updated Basket with refreshed guest entries.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

post/shop/basket/{basketId}/vouchers

Apply a voucher to a Basket

createBasketVoucher

Redeems a VoucherCode against the basket as a payment method. Trybe-issued vouchers carry a remaining balance and are partially or fully applied to the basket total; external vouchers (from a third-party voucher integration) are validated with the provider and held against the basket until submit.

Returns 400 Bad Request if the voucher can't be redeemed (e.g. wrong site, expired, already fully spent, or the third-party provider returned an error).

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Request body

  • codestringrequired

    The customer-visible voucher code to redeem. May be a Trybe-issued code or a code provisioned by an external voucher integration connected to the site.

Responses

  • 200

    The updated Basket with the voucher applied.

  • 400

    The request failed.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

  • 422

    The request didn't pass validation

delete/shop/basket/{basketId}/vouchers/{voucher}

Remove a voucher from a Basket

deleteBasketVoucher

Detaches a previously-applied VoucherCode from the basket. Any balance the voucher was contributing is released back to the voucher and basket totals are recalculated.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

  • voucherobject-idrequired

    The unique identifier of the VoucherCode to remove from the basket.

Responses

  • 204

    The voucher was successfully removed from the basket.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 404

    The resource couldn't be found

get/shop/basket/{basketId}/offered-retail-products

List cross-sell retail products for a basket

listBasketOfferedRetailProducts

Returns a curated list of retail Products to offer to the customer during checkout. Selection is driven by the current basket contents: a product appears here if it is configured as a cross-sell on any of the basket's existing line items.

The intended consumer is the storefront's "you may also like" panel on the checkout screen. The list is unpaginated and site-scoped to the basket's site.

Path parameters

  • basketIdobject-idrequired

    The unique identifier of the Basket.

Responses

  • 200

    The cross-sell products were successfully retrieved.

  • 401

    The user is unauthenticated

  • 404

    The resource couldn't be found

post/shop/memberships

Create a membership order

createMembershipOrder

Creates a new basket for the membership purchase and produces the Membership against the given customer. Use this when the storefront has already collected the membership type, rate and target customer and you want to skip straight to a payment-ready basket.

The returned Membership will be in reserved state — call the customer-side confirmMembership endpoint once the basket is paid to activate it.

Request body

  • customer_iduuidrequired

    The customer the membership is being purchased for.

  • site_iduuidrequired

    The site the membership belongs to.

  • membership_type_iduuidrequired

    The MembershipType being purchased.

  • membership_rate_iduuidrequired

    The chosen MembershipRate within the type.

  • start_datedateoptional

    The date the membership should start, as YYYY-MM-DD. Defaults to today when omitted.

  • end_datedateoptionalnullable

    The date the membership should end, as YYYY-MM-DD. Omit (or pass null) for evergreen memberships that run until cancelled.

  • payment_method_idstringoptionalnullable

    Optional ID of a payment method already on file for the customer. When provided it must reference a payment method belonging to customer_id; pass null (or omit) to skip attaching one at order-creation time.

  • sourcestringoptional

    Where the membership purchase originated. self_signup indicates the public self-signup flow, app indicates the back-office app, and import is reserved for bulk imports.

    Possible values:self_signupappimport
  • external_refstringoptionalnullable

    Optional external reference for the membership purchase (e.g. an ID from a PMS or partner system).

Responses

  • 201

    The membership order was successfully created.

  • 401

    The user is unauthenticated

  • 403

    The authenticated user does not have permission.

  • 422

    The request didn't pass validation