- List services —
GET /storefront/products - Pick a staff member —
GET /storefront/staff-members - Fetch available time slots —
GET /storefront/products/{productId}/current-availabilities - Create an appointment —
POST /storefront/appointments - Add it to a cart —
POST /storefront/cartandPOST /storefront/cart/items - (Optional) Show and attach add-ons —
GET /storefront/products/{productId}/add-onsandPOST /storefront/cart/add-ons - Check out —
POST /storefront/cart/checkout/startandPOST /storefront/cart/checkout/submit
Setup
Install the SDK in a Next.js project and initialize it once, for example in a small module imported by your server code:lib/opencals.ts
List services
ProductService.list() wraps GET /storefront/products and returns a paginated list of active services:| Field | What it means for your booking page |
|---|---|
duration | Service length in seconds |
price | Price (0 = free); minPrice/maxPrice for variable pricing |
maxAttendees | Greater than 1 → show an attendee count selector |
isCustomDuration | true → show a date-range picker instead of single slots |
staffMembers | If populated, let the customer pick a staff member |
locations | If populated, let the customer pick a location |
Let the customer pick a staff member
For salons and similar businesses, customers often choose who they book with. The selected staff member’s
StaffMemberService.list() wraps GET /storefront/staff-members:id filters availability in the next step. The same pattern works for locations via LocationService.list() (GET /storefront/locations) on multi-location stores.Fetch available time slots
ProductService.getCurrentAvailabilities() wraps GET /storefront/products/{productId}/current-availabilities. It takes a required date (YYYY-MM-DD) plus optional staffMemberId, locationId, and timezone filters:For custom-duration products (
isCustomDuration: true, e.g. rentals or venue hire), use GET /storefront/products/{productId}/current-availability-ranges and show a date-range picker instead. There’s also GET /storefront/products/{productId}/nearest-availability for “next available slot” badges on service cards.Create the appointment
When the customer picks a slot, create an appointment with
POST /storefront/appointments. The required slot object carries the product and the UTC date/time range; staffMemberId and locationId are optional:Cart
Carts hold appointments between slot selection and payment, and they expire after a few minutes so abandoned selections release their slots. Cart endpoints identify the cart with the Persist
X-Cart-Id header:cart.id (for example in a cookie) so the customer keeps their cart across pages. If checkout takes a while, POST /storefront/cart/extend adds five minutes to the cart’s expiration.Show and attach add-ons (optional)
If the service has add-ons (extras like equipment rentals, upgrades, or accessories), fetch them and let the customer choose before proceeding to payment.When the customer selects an add-on, attach it to the cart item:A few things to know about add-on pricing:
| Field | What it means |
|---|---|
price | Unit price. Multiply by quantity for the line total. |
durationMultiplied | If true, quantity is auto-set to the service duration units (e.g., 3 days = quantity 3). Don’t ask the customer for quantity. |
maxQuantity | If non-null, cap your quantity input at this value. |
Skip this step if
addOns.data is empty — not every service has add-ons configured.Checkout
Checkout is a three-call sequence against the same Save the customer so the order and appointments have contact details (guests don’t need an account):If the store has custom checkout questions, fetch them with The response includes the created
X-Cart-Id.Start validates the cart and initializes payment with your chosen provider (list configured providers with GET /storefront/payment/providers):GET /storefront/cart/checkout/questions/{language} and save answers via POST /storefront/cart/checkout/save-answers.Submit captures the payment and creates the order:order and, for new customers, an auth token pair you can use to sign them in automatically — see Authentication.For pay-at-venue stores, start checkout with
provider: "cash" and submit directly with no payment confirmation step.After the booking
With a customer token you can power a full self-service portal:GET /storefront/appointments— list the customer’s appointmentsPUT /storefront/appointments/{appointmentId}/reschedule— move a bookingPUT /storefront/appointments/{appointmentId}/cancel— cancel itGET /storefront/orders— order history with payments and refunds