Inspect the contract. Build against generated truth.
This reference reads the same typed endpoint registry that generates Booking Bible’s OpenAPI 3.1 document. Start with a group, then open only the parameters and examples you need.
Route handlers are the complete deployed /api/v1 surface. Documented operations are the partner-facing contracts currently registered for OpenAPI.
Start with the contract
Authentication and versioning are explicit
Public discovery routes need no credentials. Protected routes accept a user bearer token, an organization-scoped API key, or the method documented for that operation.
Organization-scoped credentials
Create API keys under Admin → Settings → Developer. Each key is shown once, carries explicit scopes, and remains bound to its venue.
Version pinned by header
Send X-Api-Version to pin behavior. The current documented version is 2026-04-11.
Groups and operations below are generated from the application registry. Download the OpenAPI JSON for code generation or machine-readable inspection.
Discovery20 documented operations
GET/api/v1/discoveryPublic
Discover live venue inventory
Bounded, paginated Universe discovery for one canonical world and venue-local date. Returns capped live class or service/appointment summaries with explicit partial failures; member coordinates are not accepted.
Parameters, scopes and examples
Query parameters
worldstring · required
Required: classes, treatments, or salon
datestring · required
Required venue-local date (YYYY-MM-DD)
time_windowstring
any, morning, afternoon, or eveningDefault: any
searchstring
Venue, location, class, or service search
pageinteger
Page numberDefault: 1
limitinteger
Venue items per page (max 4)Default: 4
GET/api/v1/discovery/countsPublic
Live per-world "open today" venue counts
Lightweight counterpart to /api/v1/discovery for the Explore landing screen: how many venues actually have live same-day inventory in each world today, not how many venues merely support the world. Reuses the same same-day-activity signals as discovery ordering (classes: class_instances existence; treatments/salon: the union of provider_schedules rostering and real appointments existence — a same-day proxy, not exact slot availability).
Full venue profile including brands, locations with rooms, opening hours, amenities, and photos.
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/joinBearer token
Check venue join eligibility
Bearer-authenticated, read-only membership check for Consumer apps. Resolves the target from its slug or organization UUID and reports member, can_join, or an unavailable reason without changing account state.
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug or organization UUID
POST/api/v1/venues/{slug}/joinBearer token
Join a venue with explicit consent
Bearer-authenticated and Idempotency-Key protected. Requires {consent:true}; creates one active member relationship without changing an existing role, assigns the venue client ID, and emits the canonical audit, analytics, and member.created integration events.
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug or organization UUID
Explicit user consent to add this venue to their account.
Request body
{
"consent": true
}
GET/api/v1/venues/{slug}/schedulePublic
Get class schedule
Live class schedule with real-time availability. Filter by date range, location, brand, class type, instructor, or online-only. Each row includes the additive general-policy `requires_workshop_entry` flag and a nullable public `workshop_entry_target`; `is_bookable` retains its capacity/status/time meaning.
Bearer-authenticated exact class detail for Consumer push deep links. Requires X-Organization-ID for an active member relationship, retains public/member-entitled completed or cancelled classes, and never exposes an unlisted class. Includes the same additive general-policy `requires_workshop_entry` and nullable public `workshop_entry_target` fields as the venue schedule; `is_bookable` remains capacity/status/time-only.
All active pass types with pricing tiers, binding commitments, class restrictions, and location availability. Returns an `{ org, pass_types }` envelope (BB-R4): `org` carries `slug`, `name`, `currency`, `timezone`, and `vat_exempt_age_threshold` (for an under-/over-threshold pricing toggle); each `pass_types` entry includes its `slug` for `/buy/{slug}` deep-links. Configurable recurring entries also include `pricing_mode`, billing cadence, the immutable active pricing version, quantity range/step, volume tiers, unlimited option, and change-cycle policy. Optional `category`, `location_id`, `brand_id` filters apply to `pass_types`.
Class catalog with descriptions, difficulty levels, durations, and included services.
Parameters, scopes and examples
Required scopes
read:classes
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/instructorsPublic
Get instructors
Instructor profiles with bios, photos, and specialties.
Parameters, scopes and examples
Required scopes
read:instructors
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/locationsPublic
Get locations
Physical locations with rooms, capacity, opening hours, amenities, and Google Maps integration.
Parameters, scopes and examples
Required scopes
read:locations
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/brandsPublic
List brands
Active brands at this venue. Each entry includes identity (name, slug, description), theming (colors, logo, hero), social links, and a class_types_count for quick summary rendering.
Parameters, scopes and examples
Required scopes
read:brands
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/brands/{brandSlug}Public
Get brand detail
Full brand record plus class_types tagged to this brand and the pass_types available for it (respecting pass_type_brands restrictions — passes with no brand-junction rows are venue-wide and are included).
Parameters, scopes and examples
Required scopes
read:brands
Path parameters
slugstring · required
Venue URL slug
brandSlugstring · required
Brand slug within the venue
GET/api/v1/geoPublic
Geo prefill for the signup form
Anon utility that reads Vercel's request-geo headers (`x-vercel-ip-country`/`x-vercel-ip-city`) so a client can prefill signup's optional `country`/`city` fields from the caller's own IP before submitting POST /api/v1/auth/signup. `country` is an ISO 3166-1 alpha-2 code; `city` is URI-decoded free text. Either is `null` when the header is absent (e.g. local dev). No DB touch; never cached (per-caller response).
PUBLIC (no auth) balance-by-code lookup for a venue gift card, for a storefront "check your balance" widget. Org resolved from {slug}; lookup scoped to that org's cards by the FULL code. Returns the minimal `{ code, remaining_amount, currency, status, expires_at }` — never purchaser/recipient PII. Enumeration-hardened: an unknown code, a cross-org code under the wrong slug, and a cancelled card all return the SAME generic 404. IP rate-limited (20/min).
PUBLIC (no auth) gift-card preview so a BRANDED storefront can show a recipient what they were gifted ("Alex sent you a 3-month membership") before prompting signup/redeem — instead of bouncing them to BB's /gift/redeem/[code] venue portal. Returns `{ code, gift_type, sender_name, gift_description, amount, currency, status, expires_at }` — the sender's display name + a human gift description only, NEVER recipient/purchaser contact info, the personal message, or the redeemer. Enumeration-hardened: unknown code, wrong slug, and a cancelled card all return the SAME generic 404. IP rate-limited (20/min). Redeem itself is member-authenticated (POST /api/v1/gift-cards/redeem).
Member-authenticated request-a-booking for a service that accepts inquiries (`accepts_inquiries: true` on the public services list). Free-text preferred time, not a real slot — the venue converts it to a real appointment once a time is agreed. `Idempotency-Key` is optional but MUST be a UUID when sent (400 `INVALID_IDEMPOTENCY_KEY` otherwise); it is the database ingest request id. Every 201 and every 503 `INQUIRY_RECONCILE_FAILED` returns an `Idempotency-Key` RESPONSE header (mirrored as `error.details.request_id` on the 503) carrying the identity the inquiry was accepted under — your key when you sent one, the server-generated UUID when you did not. Retry a 503 with that exact value as `Idempotency-Key`: it replays the accepted inquiry (no second row) and re-drives only what is still missing. Retrying without it mints a new identity and files a duplicate inquiry. Rate-limited 10/min. Errors: 503 INQUIRIES_DISABLED (kill switch off), 404 NOT_FOUND (venue), 422 SERVICE_NOT_ACCEPTING_INQUIRIES, 422 VALIDATION_FAILED, 409 IDEMPOTENCY_KEY_REUSE_MISMATCH (same key, different answers — nothing written), 500 SUBMIT_FAILED (`details.reason` passthrough).
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug
Inquiry details
Request body
{
"service_id": "uuid",
"preferred_time": "Tuesdays or Thursdays after 17:00",
"message": "Looking for a 90-minute deep tissue session.",
"contact_name": "Jane Doe",
"contact_email": "jane@example.com",
"contact_phone": "+4520123456"
}
Response example
{
"data": {
"id": "uuid"
},
"error": null
}
GET/api/v1/me/inquiriesBearer token
My booking inquiries
The caller's own booking inquiries across every venue, newest first. Status is mapped to plain language (never the raw form_submissions enum): 'Sent — waiting for the venue', 'The venue replied', or 'Closed'; archived/spam/deleted rows are never returned.
Exchange a device-bound mobile token_hash or a 6-digit email OTP for a session. Mobile token hashes require the callback request_id and device-held code_verifier. Rate-limited 5/10 min per IP.
Check whether an email already has an account before signup. Returns a state hint (absent | active | password_never_used | imported_unclaimed | unknown). Rate-limited 20/min per IP. Constant-time floor of 250ms to prevent enumeration.
Create a TOTP challenge for one of the caller's factors. Returns {id, expires_at}; pass the id as challenge_id to /auth/mfa/verify. Repeating mints a fresh challenge (intended resend). Rate-limited 5/min per user.
Verify a 6-digit TOTP code (enrollment confirmation or login challenge). Accepts {type: totp, factor_id, code}, {type: backup_code, code}, or the challenge-bound {challenge_id, code} (factor resolved from the preceding /mfa/challenge). Rate-limited 5/5 min per user.
Generate 10 single-use backup codes for MFA recovery. Previous unused codes are invalidated. Codes are shown once in plaintext — only hashes are stored.
Parameters, scopes and examples
Response example
{
"data": {
"backup_codes": [
"ABCD1234EF",
"..."
],
"warning": "Save these codes securely. They will not be shown again.",
"count": 10
}
}
POST/api/v1/auth/mfa/resetBearer or API key
Admin MFA reset
Admin-initiated MFA reset for a user. Unenrolls all factors and invalidates backup codes. Permission: admin.users.manage.
Exchange refresh token for new access and refresh tokens.
Parameters, scopes and examples
Refresh token
Request body
{
"refresh_token": "xxx"
}
POST/api/v1/auth/logoutBearer token
Log out current session
Revoke the refreshable Supabase session represented by the caller JWT. The access JWT remains valid until its encoded expiry.
Parameters, scopes and examples
Response example
{
"data": {
"ok": true
}
}
POST/api/v1/auth/password/forgotPublic
Forgot password
Send a single-use 6-digit password verification code. Honours venue branding when an org is identified and never reveals whether the email exists. No reset link is generated.
Authenticated password change that still requires a fresh single-use numeric code. Submit the code and new password together; current-password-only and session-only changes are rejected.
NAMASTE-GATES-01 — mint a one-time SSO handoff code (60s TTL, single-use, SHA-256 hashed at rest) bound to an allowlisted destination domain. The destination site exchanges it at /auth/handoff-exchange for a fresh session.
NAMASTE-GATES-01 — consume a one-time handoff code (atomic single-use) and receive a fresh Supabase session for the bound user. Same session shape as /auth/login.
TV-DEVICE-AUTH-01 — RFC 8628-style device authorization (mint side). An input-constrained device (TV) receives a 256-bit device_code (its poll credential) plus a short user_code (shown as XXXX-XXXX + QR). Both are SHA-256 hashed at rest, bound to one 10-minute expiry, single-use.
TV-DEVICE-AUTH-01 — a SIGNED-IN member submits the user_code shown on the TV (normalized: uppercase, dashes/spaces stripped). Binds the pending device code to the caller so the TV poll returns a session. Every failure (unknown / expired / attempts-capped) is the same generic 400 INVALID_CODE; per-code attempts<5 cap.
Parameters, scopes and examples
The short code shown on the TV
Request body
{
"user_code": "ABCD-EFGH"
}
Response example
{
"data": {
"approved": true
}
}
POST/api/v1/auth/device/tokenPublic
Poll TV device code for session
TV-DEVICE-AUTH-01 — the TV polls with its device_code (every `interval` seconds). 400 AUTHORIZATION_PENDING until approved; 400 EXPIRED_TOKEN / 403 ACCESS_DENIED / 400 INVALID_CODE are terminal. On approval the code is consumed atomically (single-use) and a fresh Supabase session is returned — same shape as /auth/login.
Venue-local YYYY-MM-DD start of a pass usage cycle (inclusive). Requires organization_id.
cycle_endstring
Venue-local YYYY-MM-DD end of a pass usage cycle (exclusive). Requires organization_id.
afterstring
Cursor for pagination
limitinteger
Items per pageDefault: 20
POST/api/v1/bookingsBearer or API key
Book a class
Create a booking. Validates pass eligibility, capacity, booking window, daily limits, and class restrictions. Supports idempotency via Idempotency-Key header.
Retrieve a single booking with class details, pass info, and check-in status.
Parameters, scopes and examples
Required scopes
read:bookings
Path parameters
idstring · required
Booking ID
POST/api/v1/bookings/buddyBearer token
Invite a client to the same class
Creates and emails a venue-branded invitation to an existing active client at the same venue. The inviter must already have a confirmed booking. The recipient books with their own pass or payment; no guest funding or inviter entitlement is used. Idempotency-Key supported.
Accepts a buddy invitation for the authenticated recipient and books the same class with that recipient’s own eligible pass or normal venue booking rules. The invited email/account and active venue membership must match. Idempotency-Key supported.
NAMASTE-GATES-01 / LIVE-PARTICIPATION-01 — entitlement-based live-watch path. Requires an active pass whose type grants online class access and covers the class type; finds or creates the caller’s attendance_type=online booking (idempotent, respects online_capacity, consumes a clip only for clip-based passes) and returns a signed Mux playback URL plus viewer-session telemetry token. First admission opens 10 minutes before start and closes exactly at start; an admitted viewer may recover through end + 5 minutes unless they explicitly leave after start.
Client-facing: exchange a valid QR token for a check-in on the caller's booking. Token must be active and not expired. Anti-replay: a booking can only transition to checked_in once. Every scan writes an audit_log entry regardless of outcome.
Pass-type catalog detail used by checkout — price, duration, benefits, binding tiers, eligible class types, and the published flexible recurring configuration when enabled. Active public items need no authentication; a hidden exhausted-credit target requires member JWT authentication plus its clips_empty_offer_id capability.
Parameters, scopes and examples
Path parameters
idstring · required
Pass-type id
Query parameters
clips_empty_offer_idstring
Opaque clips-empty path UUID. Revalidated against the authenticated member’s exhausted, still-valid source pass before a hidden target is returned.
Initiate pass purchase. Returns a PaymentIntent or SetupIntent client_secret (`client_secret_type` identifies which) with the provider-frozen customer, ephemeral key, Connect account, merchant country, and regional revision. Customer credentials are paired and may both be null only for a supported generic-sheet/no-customer result. Optional binding_months must identify a current server-side tier and is priced by the same canonical resolver as checkout preview; unavailable tiers return 422 rather than falling back. Configurable recurring passes require selection_kind=quantity with quantity, or selection_kind=unlimited. Fixed passes support promo codes, gift cards, and account credits.
MEMBER (JWT) redeem endpoint so a branded storefront can host the whole redeem flow on its own domain. Applies the gift `{ code }` to the caller's account: a custom-amount gift credits the balance (`{ type:"credit", amount, newBalance }`); a pass gift creates + activates a pass (`{ type:"pass", passId }`). Atomic SELECT FOR UPDATE claim — two concurrent calls can never both redeem. A logged-out recipient must sign up / log in first (that creates/links the BB member); this endpoint is member-only by design. Org from the caller's active membership (X-Organization-ID header or single membership). Errors: 401 UNAUTHORIZED, 403 NO_ORG / MODULE_DISABLED, 400 VALIDATION_ERROR, 404 INVALID_CODE, 409 ALREADY_REDEEMED / EXPIRED / NOT_AVAILABLE, 500 REDEEM_FAILED.
Parameters, scopes and examples
Gift card code to redeem onto the caller's account
Gift cards the caller purchased or received (buyer, redeemer, or addressed recipient email), scoped to the active org. Returns `{id, code, initial_amount, balance, currency, status, recipient_email, recipient_name, message, expires_at, created_at}` with status `active|redeemed|expired|void`. Degrades to an empty list when the gift_cards module is off or no org context resolves.
POST/api/v1/gift-cards/purchaseBearer token
Purchase gift card
Buy a gift card (custom amount or a gifted pass) for a recipient. Creates a Stripe one-time PaymentIntent and returns client_secret plus customer_id + ephemeral_key for the Stripe Payment Sheet. Gated on the gift_cards module. Idempotency-Key supported.
Parameters, scopes and examples
Gift card purchase
Request body
{
"gift_type": "custom_amount",
"organization_id": "uuid",
"amount": 500,
"sender_name": "Alex",
"recipient_name": "Jordan",
"recipient_email": "jordan@example.com",
"delivery_method": "email",
"personal_message": "Enjoy a class on me!"
}
Anonymous (or logged-in) native gift-card checkout — phase 1. Mints a Stripe PaymentIntent for a gift card and returns client_secret so the buyer can mount Stripe Elements in a modal. Two gift kinds (exactly one of the two fields): a CUSTOM-AMOUNT gift via `amount` (smallest currency unit, min 5000, max 5000000), or a PASS-BASED gift via `pass_type_id` (GIFT-PASS-API-01 — must be an active, giftable, non-intro pass type of this org; price is server-resolved via calculateGiftPrice, optional `duration_months` 1–120 prepays a recurring membership). The gift_cards row is created only on confirm, so an abandoned payment leaves no orphan. Anonymous callers must pass a Turnstile token. VAT is accounted at redemption (multi-purpose voucher) so vat_amount is 0. Gated on the gift_cards module. Rate-limited 10/min.
Parameters, scopes and examples
Gift card checkout — custom-amount example; for a pass gift replace `amount` with `pass_type_id` (+ optional `duration_months`)
Request body
{
"organization_slug": "hot-yoga-cph",
"amount": 50000,
"recipient_email": "jordan@example.com",
"recipient_name": "Jordan",
"sender_name": "Alex",
"message": "Enjoy a class on me!",
"giver_email": "alex@example.com"
}
Native gift-card checkout — phase 2. After the buyer confirms the PaymentIntent client-side, this creates the gift_cards row (custom-amount OR pass-based — the pass identity rides in PI metadata), delivers it to the recipient, and emails the giver a receipt. Idempotent on the PaymentIntent — a retry or the webhook backstop never double-creates a card. Returns the last 4 of the code, a masked recipient email, and gift_type. organization_slug is optional but recommended for direct-charge venues.
Pause (freeze) a pass for a date range. Owner-scoped. Enforces the pass-type pause rules (allow_pause, min/max duration, annual freeze budget) + binding gate, pauses Stripe billing, and bills any pause fee. Idempotency-Key supported.
Move a deferred (pending_activation) membership start to today or an earlier future date: re-anchors Stripe billing, charges the first membership payment, and activates the pass. Owner-scoped. Idempotency-Key supported; rate-limited 5/min. Returns payment_status succeeded | requires_action (confirm with client_secret; the invoice.paid path then activates) | pending. Errors: PASS_NOT_FOUND, FORBIDDEN, ALREADY_STARTED, IN_PROGRESS, INVALID_START_DATE, PAYMENT_FAILED, STRIPE_UNAVAILABLE.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
New start date (must be earlier than the current start)
Owner-scoped, read-only termination summary resolved from the venue self-cancel gate, binding period, termination policy, Stripe billing boundary and remaining class balance. Returns can_confirm=false with the blocking reason while a binding period is active.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
POST/api/v1/me/passes/{id}/terminateBearer token
Terminate a recurring membership
Confirmed owner-scoped membership termination. Enforces venue allow_member_cancel, minimum membership age, binding period, required reason and the configured termination boundary. Stripe synchronization is fail-closed and Idempotency-Key is supported.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
Explicit acknowledgement and optional/venue-required reason
Request body
{
"acknowledged": true,
"reason": "Moving away"
}
GET/api/v1/me/passes/{id}/extensionBearer token
Get pass extension quote
Return the authenticated member’s venue-scoped self-extension policy and live quote: proposed expiry, price/currency, configured duration, remaining extension allowance, clips, and a machine-readable unavailable_reason. Requires X-Organization-ID and fails closed on invalid venue configuration.
Revalidates the venue’s live self-extension policy and creates a durable operation before any processor call. Paid responses include PaymentSheet customer/ephemeral-key credentials in the exact frozen Stripe namespace; direct mode returns stripe_account_id. Free responses still return operation_id but do not mutate the pass. Requires X-Organization-ID and Idempotency-Key.
Authoritatively rechecks owner, tenant, venue policy, maximum count, hard end, frozen Stripe provenance and payment status under database locks. Paid success atomically records payment, fee, audit, pass, and operation; explicit post-charge conflicts are idempotently refunded. Nonterminal 202 statuses are finalizing or refund_pending and are safe to retry. The Stripe webhook shares this reconciler. Idempotency-Key is required.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
Durable operation reference plus PI reference for paid extensions
Request body
{
"operation_id": "uuid",
"payment_intent_id": "pi_xxx (omit when free)"
}
Accept a pending pass-share invitation by token. Verifies the caller’s email matches the invite recipient, then grants booking access by appending the caller to `passes.shared_with` (respecting `pass_types.max_sharers`) and converges the share into the `pass_shares` table. Emits `pass.share_accepted`. Member-JWT. Idempotency-Key supported.
Published VODs and class replays for the caller's venue. Visibility public + members only; pass_restricted items are accessible via /video-catalog/:id once the pass check passes. Signed Mux playback URLs valid for 2 hours.
Parameters, scopes and examples
Query parameters
pageinteger
Page numberDefault: 1
limitinteger
Items per page (max 50)Default: 20
categorystring
Filter by category (class_recording | tutorial | workshop)
The caller's required/pending intake forms for their active org. Each entry is annotated with whether the member already submitted (the pre-booking form gate's source of truth). Returns [] when the `forms` module is disabled.
Parameters, scopes and examples
Response example
{
"data": [
{
"id": "uuid",
"slug": "new-client-intake",
"name": "New Client Intake",
"description": "Tell us about your practice and any injuries.",
"required": true,
"submitted": false,
"submission_id": null,
"submitted_at": null
}
]
}
GET/api/v1/forms/{id}Bearer token
Get form schema
Render schema (fields, steps, submit label) plus the venue's configured `legal_basis` (`consent` | `contract` | `legitimate_interest` | `legal_obligation`) for a single published form. Use `legal_basis` to render the matching privacy notice and, for a `consent` form, to present its required consent checkbox as the gate it is — a consent-basis submission is refused unless that box was ticked. Scoped to the active org — forms in other orgs return 404.
Parameters, scopes and examples
Path parameters
idstring · required
Form UUID
Response example
{
"data": {
"id": "uuid",
"slug": "new-client-intake",
"name": "New Client Intake",
"description": "Tell us about your practice and any injuries.",
"required": true,
"legal_basis": "consent",
"schema": {
"version": 1,
"fields": [],
"steps": null,
"submit_label": "Submit"
},
"thank_you": {}
}
}
POST/api/v1/forms/{id}/submitBearer token
Submit a form
Submit `{ answers }` for a published form. Validates required fields + types, persists a submission stamped with the caller, and routes it into the unified inbox. `Idempotency-Key` is optional but MUST be a UUID when sent (400 `INVALID_IDEMPOTENCY_KEY` otherwise) — it is both the HTTP replay token and the database ingest request id. The same key with the same answers replays the original response; the same key with different answers writes nothing and returns 409 `IDEMPOTENCY_KEY_REUSE_MISMATCH`, so mint a new key whenever the answers change. Every 201 and every 503 `SUBMIT_RECONCILE_FAILED` returns an `Idempotency-Key` RESPONSE header (mirrored as `error.details.request_id` on the 503) carrying the identity the submission was accepted under — your key when you sent one, the server-generated UUID when you did not. Retry a 503 with that exact value as `Idempotency-Key`: it replays the accepted submission and re-drives only the missing delivery. Retrying without it mints a new identity and files a duplicate. 422 with `details.missing[]` on required-field failures; 422 `CONSENT_REQUIRED` when a consent-basis form was sent without its consent box ticked; 409 `FORM_CONSENT_MISCONFIGURED` when the form itself cannot lawfully collect.
The caller's referral status for their active org: code, referred-friend count, conversions, rewards earned, and an anonymized (first-name + last-initial) per-referral list. Returns an empty summary when the `referrals` module is disabled.
Active public venues ranked by explicit favourite, then canonical pass, class-booking, and appointment signals. Returns counts and last activity; caller identity is server-bound.
Idempotently removes only the authenticated member and requested venue pair.
Parameters, scopes and examples
Path parameters
organizationIdstring · required
Venue organization UUID
GET/api/v1/me/credits/balancesBearer token
My venue credit balances
Complete ledger-derived balances grouped by venue and currency. Each row carries `balance` (the venue ledger total), `available` (that total minus credit held by open checkout reservations, which is what checkout will actually spend) and `reserved`. Amounts are in major units. Consumer is account-wide; branded requests are fail-closed to x-organization-slug.
POST/api/v1/me/avatar/upload-urlBearer token
Create avatar upload ticket
Returns a caller-owned, MIME-bound storage path and two-hour signed upload URL for PNG, JPEG, or WebP up to 5 MB.
PATCH/api/v1/me/avatarBearer token
Finalize my avatar
Validates caller path ownership, metadata, size, and image magic bytes before deriving and saving the public URL.
DELETE/api/v1/me/avatarBearer token
Remove my avatar
Idempotently clears the profile reference and removes only the caller-owned canonical avatar object.
GET/api/v1/me/workspace-profileBearer token
My active venue operating profile
Server-authoritative Business-app profile for the active venue selected by X-Organization-ID. Returns booking_mode (classes, appointments, or both), business_type, resolved class/appointment operation gates, venue surface applicability, appointment access/counts, active_modules, and the resolved vertical_modules visibility map. business_type is informational and never used to infer booking_mode. Surface values are venue-level applicability; clients must still intersect them with the caller's effective permissions from GET /api/v1/me.
Current user profile with all active venue memberships and roles. Each membership carries `permissions: string[]` (the caller's OWN effective permission keys for that org — per-user overrides applied over role/capability defaults, resolved identically to requireApiPermissionWithDefaults) and `capabilities: string[]` (the membership capability set, surfaced for every membership). To bound per-request cost in this multi-tenant app, `permissions` is resolved for the ACTIVE org only (top-level `permissions_scope: "active_org"`; non-active memberships carry `[]`) — mobile refetches /me on org switch. Workspace ownership is server-projected as `is_individual`, `is_owned`, `is_workplace`, `is_relationship`, `is_selectable`, and an explicit `workspace_group` (`owned`, `works_at`, `member_venues`, or `relationships`). Accepted role-bearing employer memberships remain selectable in Business under “Works at”; member-only Network relationships do not. Business clients must only put selectable rows in their workspace picker. Gates UI on these instead of discovering denials via 403s. A PATCH /admin/permissions/user/{userId} is reflected within ≤60s (permission-cache TTL). Caller's own permissions only. See docs/api/ME_PERMISSIONS_CONTRACT.md.
POST/api/v1/me/active-organizationBearer token
Switch my active workspace
Authoritatively switches the caller to an active, selectable workspace. When the caller owns an individual professional venue, accepted role-bearing employer memberships remain selectable; only non-operational/member-only relationships return WORKSPACE_NOT_SELECTABLE. The response includes effective permissions for the selected workspace so native role gating is safe immediately.
Resolved feature-module map for the caller's active org (C07): `{ <module_key>: { enabled, source, tier?, settings? } }` — the same four-tier resolution (plan → group → venue → tenant) the admin sees at /admin/features. Also includes `professional_collaborations`, which reflects the platform-wide teacher-settlements rollout independently of the venue-to-venue `network` plan gate. Drives every <FeatureGate> in the branded mobile app. Multi-membership callers must send X-Organization-ID; without it the map resolves empty (all off).
GET/api/v1/me/minimalPublic
Minimal auth check
Cross-origin auth check for venue marketing sites. Returns { logged_in, first_name, venue_id, preferred_brand_id } — or logged_in=false when no session. CORS is gated by the venue/brand embed_allowed_origins allowlist; unknown origins get no CORS headers (treated as "not logged in" by the caller).
GET/api/v1/me/entitlementsBearer token
My entitlements
NAMASTE-GATES-01 — the caller's entitlement matrix for one venue: can_book_physical (any active pass with grants_in_person), can_watch_online (grants_online_class_access), online_only, bookable_class_type_ids ("all" when any usable pass is unrestricted), and an active_passes[] summary (slug, category, grants, validity, clips). The create_booking RPC enforces the same matrix atomically.
Create an account-local Stripe SetupIntent plus matching Customer/ephemeral-key credentials. Requires an Idempotency-Key header. The response freezes the server-owned venue country and exact Connect account for native Payment Sheet initialization.
Promote a saved card to the Stripe customer default (invoice_settings.default_payment_method). Empty body, idempotent via Idempotency-Key. GET /me/payment-methods then returns is_default:true on the matching row (PAY-P3.1).
Parameters, scopes and examples
Path parameters
idstring · required
Stripe payment method ID
POST/api/v1/me/payment-sheet-initBearer token
Initialise Payment Sheet
Setup-only flow for Stripe Payment Sheet (PAY-P1.1). Requires an Idempotency-Key header. Returns customer_id, ephemeral_key, setup_intent_client_secret, and apple_merchant_id in the exact SetupIntent home account: connected only in direct mode, otherwise platform. Use when collecting a saved card before any purchase.
Register an Expo push notification token for iOS/Android/web. app_variant is required so member, branded-venue, and staff deliveries cannot cross application boundaries. Branded and business tokens also require a validated organization context.
Deactivate the authenticated user's token or device before logout. The token/device selector is sent in the JSON body.
Parameters, scopes and examples
At least one token or device_id is required
Request body
{
"device_id": "installation-uuid"
}
GET/api/v1/me/notificationsBearer token
Notification history
Cursor/page-paginated email, SMS, push, and in-app history. Rows include source-aware `data`, `read_at`, and `app_variant`; X-App-Variant filters app-specific inbox events, while X-Organization-Slug narrows branded clients to their venue.
Self-scoped read marker. Idempotency-Key is required; another user’s row returns 404.
Parameters, scopes and examples
Path parameters
idstring · required
Notification id
POST/api/v1/me/notifications/read-allBearer token
Mark notifications read
Marks all of the caller’s unread rows read. X-Organization-Slug narrows a branded client to its exact venue; otherwise Consumer marks its cross-venue inbox. Idempotency-Key is required.
Returns the canonical ten-category catalog with effective email/SMS/push defaults, frequency caps, and per-member quiet hours for the active/requested organization.
Upserts canonical category toggles/frequency caps and quiet hours. Unknown categories are rejected and every database failure is returned; Idempotency-Key is required.
GET/api/v1/me/paymentsBearer token
List my payments
Cursor-paginated receipt-bearing payment ledger for the caller. Pending and failed attempts are excluded; successful, refunded, partially-refunded and disputed originals remain available with their payment receipt.
Parameters, scopes and examples
Query parameters
limitnumber
Page size (default 20, max 100)
afterstring
Opaque cursor from a previous page
GET/api/v1/me/invoicesBearer token
List my invoices
Cursor-paginated list of the caller's member-visible client invoices. Drafts are excluded and every row includes an authenticated document_path for the print-ready HTML invoice.
Parameters, scopes and examples
Query parameters
limitnumber
Page size (default 20, max 100)
afterstring
Opaque cursor from a previous page
GET/api/v1/me/invoices/{id}Bearer token
Invoice detail
Owner-scoped detail for one issued client invoice, including line items and the totals breakdown (subtotal, discount, VAT, total, amount_paid).
Streams the receipt PDF (application/pdf) for one of the caller's payments — branded merchant header, line items, VAT breakdown, totals. Cached in storage after first render.
Emails the venue-branded receipt PDF for one of the caller's own payments to the address already on file for their account — the same document served by the PDF download. No recipient field exists; any caller-supplied recipient is ignored. Idempotency-Key is required; a retried key replays the cached result instead of re-sending.
Parameters, scopes and examples
Path parameters
paymentIdstring · required
Payment id
Empty body — the request is never read.
Request body
{}
GET/api/v1/me/invoices/{id}/documentBearer token
Invoice print document
Authenticated owner- and venue-scoped print-ready HTML for one member-visible invoice.
Parameters, scopes and examples
Path parameters
idstring · required
Invoice id
GET/api/v1/me/refundsBearer token
List member refund receipts
Owner-scoped successful refund operations, cursor-paginated and optionally restricted by the branded organization slug. Split-tender operations are returned once with a signed negative amount.
Parameters, scopes and examples
Query parameters
limitnumber
Page size (default 20, max 100)
afterstring
Opaque cursor from a previous page
GET/api/v1/me/refunds/{refundId}/pdfBearer token
Refund receipt PDF
Owner- and venue-scoped canonical refund receipt PDF. Non-final, sibling, cross-member and cross-venue refund ids return a uniform not-found response.
Parameters, scopes and examples
Path parameters
refundIdstring · required
Refund id
GET/api/v1/me/loyaltyBearer token
Loyalty balance + history
The caller's org-scoped loyalty point balance plus a recent per-event history slice. Full paginated history is on /api/v1/me/loyalty/points.
GET/api/v1/me/loyalty/pointsBearer token
Loyalty points history
Cursor-paginated per-event loyalty point ledger for the caller.
GET/api/v1/me/streakBearer token
Attendance streak
Current + longest attendance streak, freezes remaining, and at-risk flag.
GET/api/v1/me/rewardsBearer token
Redeemable rewards catalog
Active loyalty rewards for the caller's org with affordability (is_locked) computed against the caller's balance.
POST/api/v1/me/rewards/redeemBearer token
Redeem a reward
Redeem a loyalty reward. Idempotency-Key supported; audited.
Parameters, scopes and examples
Redemption
Request body
{
"reward_id": "uuid"
}
POST/api/v1/feedbackBearer token
Submit feedback & tip
Rate a class (1-5 stars), leave a comment (optionally `anonymous`), and optionally tip the instructor via Stripe. The tip carries its own `anonymous` flag. The tip block of the response returns `client_secret`, `customer_id`, `ephemeral_key`, and `stripe_account_id` (non-null only in DIRECT charge mode).
Self-scoped class/appointment review and tip eligibility. Organization, target, settings, MobilePay capability, and prompt decision are server-derived from the owned source. Reads are side-effect-free unless `claim_prompt=true` is explicitly supplied by a prompt-mode entry check.
Parameters, scopes and examples
Query parameters
source_typestring · required
class or appointment
source_idstring · required
Owned booking id (class) or appointment id
claim_promptboolean
Reserve an in-app prompt only when true
POST/api/v1/post-attendance/reviewsBearer token
Submit class or appointment review
Creates one source-aware review after server-authoritative attendance/settings checks. Idempotency-Key required. `professional_rating`, tags, recommendation, anonymity, moderation, recipient notification, analytics, and webhooks are venue-controlled.
POST/api/v1/tipsBearer token
Tip a professional (no review)
Create a class or appointment tip in major currency units (`amount: 20` means DKK 20). Organization, professional, currency, Stripe account, and available methods are server-derived. Customer + ephemeral key are optional: customerless PaymentSheet still supports adding a card. MobilePay is returned only for verified Danish/DKK/venue-capable configurations. Idempotency-Key required.
Authenticated tipper-only reconciliation after PaymentSheet/MobilePay/3DS returns. Retrieves the server-owned PaymentIntent in its frozen Stripe account namespace, validates amount/currency/metadata, and emits receipts only after Stripe reports succeeded. Idempotency-Key required.
Parameters, scopes and examples
Path parameters
idstring · required
Tip id
GET/api/v1/tips/{id}Bearer or API key
Tip status
Poll a tip's status after confirming its PaymentIntent (incl. MobilePay / 3DS redirect returns). Access: the tipper (JWT), an org admin/manager (JWT), or an org-scoped API key. Cross-user / cross-tenant reads return 404.
Submit an Art. 15/16/17/20/21/22 request (access, erasure, portability, rectification, objection, art22 review). 30-day SLA. For erasure, account access is disabled immediately and the response reports erasure_status=pending_fulfillment; a super-admin performs the guarded erasure cascade within the SLA, while the SLA cron only alerts. Statutory records may be anonymised and retained for their legal period. Idempotency-Key required.
Parameters, scopes and examples
DSR request
Request body
{
"kind": "access",
"details": "Please send all data you have on me."
}
Re-trigger the guardian verification email for the caller's outstanding parental-consent request (C06). Matched by the authenticated email — no enumeration. Rotates the token and refreshes the 7-day expiry on the existing pending row (never a duplicate request). Empty body; Idempotency-Key supported; throttled 3/min per IP + 5/hr per user.
GET/api/v1/me/consent-statusBearer token
Active consents
Latest consent record per consent_type for the authenticated user (TOS, marketing, cookies, AI, etc). is_active is fail-closed and true only when the grant is unwithdrawn and policy_version matches the server-canonical current_policy_version; stale grants return requires_reacceptance=true.
GET/api/v1/me/consentBearer token
Current native consent state + venue requirement
The venue's photo/video consent requirement (when organization_id is given) plus the caller's version-aware state for legal, marketing, analytics, and photo/community consent types. A stale policy version is inactive and requires reacceptance.
Parameters, scopes and examples
Query parameters
organization_idstring
Resolve the venue photo-consent requirement
POST/api/v1/me/consentBearer token
Capture native consent
Grant or withdraw one supported legal, marketing, analytics, or photo/community consent for the caller. Grant versions are resolved exclusively from the server-canonical active policy; legacy client policy_version values are accepted but ignored, and an unavailable policy returns 503 without writing. Delegates to the canonical consent record/withdraw pipeline (audit + webhook).
The caller's health-questionnaire completion timestamp (completed_at, null when never submitted). Pre-check for the mobile hot-yoga booking gate.
POST/api/v1/me/health-questionnaireBearer token
Submit health questionnaire (Art. 9)
Submit the spa/hot-yoga health questionnaire for the caller's active org. Runs the Art. 9 contraindication consent gate, inserts a health_questionnaires row (plaintext responses; encrypted at rest by cron), stamps profiles.health_questionnaire_completed_at so the booking gate clears, and writes audit_log/user_events. Requires an Idempotency-Key (a double submit replays). Org resolved via X-Organization-ID / active membership.
Read the caller's external calendar-feed state: { token, enabled, generatedAt }. token is the opaque secret embedded in the public .ics feed URL (null when no feed is provisioned).
Enable the caller's external calendar feed and return the token. Idempotent — an existing token is returned unchanged (never rotated); a new one is minted (256-bit, base64url) only when absent. Empty body. Audited (calendar_feed_token_generated).
Revoke the caller's calendar feed: clears the token and disables the feed (the public feed then 404s). Empty body. Audited (calendar_feed_token_revoked).
Parameters, scopes and examples
Response example
{
"data": {
"enabled": false
},
"error": null
}
GET/api/public/calendar-feed/{token}Public
Public calendar feed
UNAUTHENTICATED — the opaque token in the path IS the credential. Returns one user's bookings as JSON for an external calendar subscription: { bookings, cancellations, userId, generatedAt }. bookings are upcoming events for the next 90 days; cancellations are bookings cancelled in the last 7 days (so calendar apps emit STATUS:CANCELLED). 404s on an unknown or disabled token (indistinguishable). Scoped strictly to the token's single user — no other user's data. 60 req/min per token.
Buyer-facing canonical PricingBreakdown for a pass type — net/VAT split, registration fee, total today + recurring, localized policy terms, the start-date window, the required legal artifacts (with already_signed), and the buyer's saved signatures. NO charge. Member-JWT + stable x-organization-id (preferred) or legacy x-organization-slug, both membership-scoped. Query: pass_type_slug (required), start_date, binding_months, locale (en|da). A selected binding tier is validated and priced server-side; unavailable tiers return 422.
POST/api/v1/me/checkout/sign-artifactBearer token
Sign a purchase-time legal artifact
Records a waiver / ToS / privacy / contract acceptance with IP + user-agent + version + signature. Idempotent on (user, document, version); a stale version → 409 force-refetch; a minor (DOB < 18) → 409 + parental consent. Supports saved-signature reuse (saved_signature_id) honouring signature_kind. Linked contracts require pass_type_slug and may include start_date; the endpoint idempotently creates/adopts the exact current-version pre-purchase contract before signing.
GUEST-INVITE-01 — whether the caller's passes qualify them to host a guest at this class, the venue guest price, the standard single-class price to strike through (compare_at_price, display only), and any invitations they already have open for it. `reason` is plain-language copy safe to render verbatim when `eligible` is false.
Creates the invitation plus its pending guest seat (a GUEST-PAY-01 `pending_payment` booking that holds NO capacity until paid). `payer:'guest'` returns the link to share; `payer:'host'` additionally returns a Stripe Checkout URL (saved card, new card, or MobilePay). `return_base_url` must be an allowlisted host or it is ignored.
Withdraws an UNPAID invitation and releases its pending seat. A paid guest spot is a real booking — cancel it through the normal booking cancellation path so the venue's refund and fee rules apply (409 `ALREADY_PAID`).
GET/api/v1/guest-invites/{token}Public
Resolve a guest invitation (public)
GUEST-INVITE-01 — the invitation landing page a friend opens. Anonymous-allowed by design (the token is the capability); returns who invited them, the class, the price and the struck-through standard price, and nothing else about the host's account. `state` is `needs_account` for a signed-out visitor, `payable` once signed in, plus `already_paid` / `cancelled` / `expired` / `class_started` / `class_full`.
POST/api/v1/guest-invites/{token}/checkoutPublic
Pay a guest invitation without an account
GUEST-INVITE-01 — the Guest Visitor branch. ANONYMOUS-ALLOWED (the token is the capability): the invited friend pays without creating an account and receives a Stripe Checkout URL. Deliberately does NOT claim the seat, so no profile is created and `bookings.user_id` stays the host. Confirmation is still the verified-payment webhook. Trade-off the calling site MUST surface: with no login, only the host or the venue can cancel it afterwards. Refuses with 409 `ALREADY_CLAIMED` once someone has linked the invitation to an account.
GUEST-INVITE-01 — the class filled up before the invited friend accepted. ANONYMOUS-ALLOWED. An unpaid invitation never held a seat, so this is a normal outcome, not an error: the friend joins the waiting list and is NOT charged. If a spot opens, `reinviteWaitlistedGuests` sends a fresh payment link. Returns `{ position, already_on_waitlist }`.
The invited friend, now signed in, takes ownership of the guest seat and gets a Stripe Checkout URL. Claiming rebinds `bookings.user_id` to their profile (the host stays on `host_user_id`), which is what makes the spot appear in their own bookings and cancellable by them under the venue's ordinary cancellation rules. Capacity is still only taken by the verified-payment confirm RPC.
Returns the authenticated member’s appointments with the exact updated_at concurrency token required for cancellation. Supports upcoming/past direction, status, venue narrowing and cursor pagination.
Parameters, scopes and examples
Query parameters
directionstring
upcoming | pastDefault: upcoming
statusstring
Appointment status
organization_idstring
Optional venue UUID narrowing
POST/api/v1/appointmentsBearer token
Book my appointment
Creates a free, pass-covered, or pay-at-venue member appointment. Paid-at-booking appointments use the checkout endpoints below. When the venue payment mode is client_choice, omit payment_choice (or send online) to pay now — installed clients that do not send a choice stay on the paid checkout path. Send payment_choice=venue only for an unpaid create. X-Organization-ID and a stable Idempotency-Key are required; client communication follows the locked member-transactional policy rather than staff-selectable channels.
GET/api/v1/appointments/{id}Bearer token
Get my appointment
Returns one owned appointment, including its updated_at concurrency token. X-Organization-ID is required.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
DELETE/api/v1/appointments/{id}Bearer token
Cancel my appointment
Atomically cancels one owned current appointment. Current clients send the exact rendered updated_at token; a stale token returns 409 STALE_TARGET and must be refreshed. Temporarily, an installed legacy member client may omit the body and the server binds its owned row snapshot to the same atomic CAS—there is no retry-without-CAS path. X-Organization-ID and a stable Idempotency-Key are required.
Read-only preview of the consequence of cancelling one owned appointment right now. The window and fee come from the service row (services.cancellation_window_hours / cancellation_fee_amount, defaults 24 / 0) — the exact pair the cancel RPC enforces — so the number shown matches the number charged. An appointment with a paid deposit or a linked payment is blocked with blocked_reason "refund_required" rather than previewing a self-service refund; a terminal appointment is blocked "not_cancellable". Honours the optional x-organization-slug tenant scope; an appointment outside the resolved scope, or belonging to another client, returns 404.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
Response example
{
"data": {
"appointment_id": "uuid",
"can_cancel": true,
"blocked_reason": null,
"cancellation_window_hours": 24,
"is_late": true,
"will_charge": true,
"fee_amount": 250,
"currency": "DKK",
"refund_expected": false,
"message": "You are inside the venue’s cancellation window, so a late-cancellation fee applies."
}
}
GET/api/v1/appointments/quoteBearer token
Preview appointment payment policy
Returns the authenticated member’s server-authoritative concrete provider, effective service price, deposit, amount due at booking, remaining venue balance, payment timing, and payment_at_booking_mode (venue | online | client_choice). An `any` provider request resolves to one currently available provider before pricing. Optional payment_choice=online|venue is honoured only when the venue mode is client_choice; omitted choice defaults to online so older clients keep paying at booking. A configured deposit still requires the deposit online. Requires X-Organization-ID.
Parameters, scopes and examples
Query parameters
service_idstring · required
Service id
provider_idstring
Provider UUID or `any`; the response contains a concrete provider UUID
start_timestring · required
ISO appointment start
payment_choicestring
Optional online | venue. Omitted = pay now when the venue lets the client decide.
Claims a durable, tenant-bound operation before creating an account-pinned Stripe PaymentIntent. Returns PaymentSheet credentials. X-Organization-ID and a stable Idempotency-Key are required.
Parameters, scopes and examples
Exact live slot and provider selection. provider_id may be a concrete UUID or "any"; the server freezes one available provider and its effective price before payment.
Retrieves the exact account-scoped PaymentIntent, requires processor status succeeded, rechecks live policy, creates the appointment idempotently, and atomically links payment/accounting. Slot conflicts are compensated with an idempotent refund; 202 finalizing states are safe to retry. The Stripe webhook uses the same reconciler.
Atomically resolves all selected resources within the API-key venue, updates independent class/workshop allowance buckets, and reconciles active participants.
Add a paid-claim website applicant to a managed course roster
Trusted server-to-server bridge for venue application forms. Resolves the API-key tenant, the pass type's managed course, the applicant client/membership, and an optional localized track name; then creates or annotates an active roster enrollment and books its upcoming course sessions. Self-reported paid_deposit/paid_full values are retained as claims requiring reconciliation and never fabricate or overwrite BookingBible payment ledger state. API-key only (write:members), rate-limited, Idempotency-Key required.
Pay for a course enrollment (early-bird-aware price, or the deposit when required). Requires an Idempotency-Key header and returns a Stripe PaymentIntent client_secret + customer_id + ephemeral_key + stripe_account_id for the Payment Sheet. The enrollment is created `unpaid`; on `payment_intent.succeeded` it flips to paid/deposit_paid and its sessions are booked (deduped on the payment-intent id). Gated on membership + venue legal docs. Member-JWT. COURSE-SUITE — the body additionally accepts optional `plan` (payment-plan id), `purchaser_type` (`individual`|`company`), and `company` details (name/VAT/address) for VAT-by-purchaser + debtor invoicing. A supplied plan must exactly match a currently offered server-side plan; only an omitted property uses legacy/default behavior. The GET `/api/v1/courses/{id}` course detail additionally returns a `staff` array — `[{ role, name, title_label, photo_url, show_on_landing_page }]` — for the landing-page teaching team (COURSE-SUITE-02 multi-trainer). CV3-03 — the GET detail also returns `payment_plans` (`{ plans: [{ id, kind, installment_count? }], collection_method }`, the normalized plan OPTIONS this purchase route accepts as `plan`) and, for an authenticated Bearer caller with an enrollment, `viewer_enrollment` (`{ id, enrollment_status, payment_status, payment_plan, amount_paid, total_amount, balance, installments: [{ installment_number, amount, due_date, status }] }`; the response is always `Cache-Control: private, no-store`).
Revenue, bookings, attendance, 30-day active clients, and average revenue per client — per brand for the given period (default last 30 days). Uses bookings.brand_id and payments.brand_id populated by HYC_2. Returns venue-wide (unbranded) totals alongside the brand rows.
Parameters, scopes and examples
Required scopes
read:reports
GET/api/v1/admin/dashboard/todayBearer or API key
Today at a glance
Today's class timeline with booking counts, check-in status, and room assignments.
Parameters, scopes and examples
Required scopes
read:schedule
GET/api/v1/admin/scheduleBearer or API key
Admin schedule
Full schedule view with internal data: per-status booking counts, notes, cancellation reasons, updated_at concurrency tokens, and fail-closed historical capabilities. include_historical=true requires scheduling.manage_history.
Parameters, scopes and examples
Required scopes
read:schedule
Query parameters
start_datestring
Inclusive ISO date/time lower bound
end_datestring
Inclusive ISO date/time upper bound
include_historicalstring
Include protected historical class rows; requires scheduling.manage_historyDefault: false
GET/api/v1/admin/appointmentsBearer token
Venue appointment schedule
Business-app venue-wide appointment list with updated_at concurrency tokens and authoritative, fail-closed historical capabilities. Filters by ISO window, direction, status, provider, and location. Permission: bookings.manage.
Parameters, scopes and examples
Query parameters
fromstring
Inclusive ISO start time
tostring
Exclusive ISO end time
directionstring
upcoming | pastDefault: upcoming
statusstring
Appointment status
provider_idstring
Provider UUID
location_idstring
Location UUID
limitnumber
Maximum 200Default: 100
POST/api/v1/admin/appointmentsBearer token
Create an appointment for a client
Creates a tenant-bound current/future appointment for a known member or contact-complete guest through the canonical atomic appointment engine. Venue-local past dates and historical attestation fields fail closed until the dedicated executor is installed. Permission: bookings.manage. Idempotency-Key required. Client delivery is default-silent: only an explicit notification_channels selection of email, sms, and/or push can send. A non-empty selection requires notifications.send and an authoritative availability preflight before the mutation; an unavailable channel fails without creating the appointment. Omitted or empty channels and legacy notify booleans remain silent.
Tenant-bound client, provider, service, location, payment, notes, lifecycle state, updated_at concurrency token, and authoritative fail-closed historical capabilities for the Business app. Permission: bookings.manage.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
PATCH/api/v1/admin/appointments/{id}Bearer token
Operate an appointment
Atomic ordinary check-in, start, complete, no-show, cancel, or reschedule with the exact expected_updated_at token returned by GET. A stale token returns 409 STALE_TARGET without mutation. Each action is checked against its canonical permission. Past/terminal appointments, past reschedule targets, and historical attestation fields fail closed until the dedicated executor is installed. Idempotency-Key required. No-show, cancel, and reschedule are default-silent and accept an explicit notification_channels selection of email, sms, and/or push; a non-empty selection requires notifications.send and an authoritative availability preflight before mutation. An unavailable channel fails without changing the appointment. Omitted or empty channels and legacy notify booleans remain silent. Check-in, start, and complete are non-client-contact actions and reject notification_channels.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
Discriminated appointment action with the opaque updated_at token returned by the appointment detail
Dedicated, atomic appointment-history command contract. Requires a UUID Idempotency-Key, appointments.manage_history plus the ordinary operation permission, REWRITE attestation, and a past effective_at. Existing-row operations require the exact expected_updated_at and expected_status returned by the appointment detail; retrocreate accepts only the closed non-financial appointment intent. Corrections are always silent and reject notification controls. The route returns 503 HISTORICAL_EXECUTOR_UNAVAILABLE without table-call fallback until the separately reviewed correct_appointment_historical database RPC is installed.
Parameters, scopes and examples
Required scopes
appointments.manage_history
Path parameters
idstring · required
Appointment UUID
Closed appointment correction; history_confirmation_token must be REWRITE
Tenant-bound class and appointment reviews for the Business app. Supports source, visibility, rating, and pagination filters. Anonymous reviewer identity is never returned. Permission: feedback.view.
Returns the consent-, preference-, contact-, and suppression-aware email/SMS reach for a venue-scoped marketing audience. Permission: marketing.flash_sales.
Returns canonical refundable headroom, payer receipt contacts, SMS availability with an explicit disabled reason, original card brand/last4, venue refund destinations, and eligibility. Native clients must use this response instead of deriving refund options locally.
Creates a venue-scoped promo and public offer, optionally dispatching a consent-gated email/SMS campaign. Idempotency-Key required. Permission: marketing.flash_sales.
Explains current automatic review-request rules and returns anonymized recent delivery outcomes. Permission: marketing.reviews.
GET/api/v1/admin/sites/statusBearer token
Website status snapshot
Returns the org-scoped venue website summary for the Business app: site identity, draft/published versions, preview URL, publish-readiness blockers/warnings, and connected custom-domain verification/SSL state. Permission: sites.view.
Parameters, scopes and examples
Required scopes
sites.view
POST/api/v1/admin/sites/publishBearer token
Publish the venue website
Publishes one tenant-bound website through the canonical publish core. Requires sites.publish plus a stable Idempotency-Key. Returns readiness blockers when the draft is not yet publishable; older mobile builds may ignore additive warnings.
Parameters, scopes and examples
Required scopes
sites.publish
Tenant-scoped website publish request
Request body
{
"site_id": "00000000-0000-4000-8000-000000000001",
"note": "Published after mobile review"
}
POST/api/v1/admin/sites/ai/chatBearer token
Talk to the website builder AI
Business-app SSE transport for the org-scoped website builder assistant. Requires sites.manage. Returns the mobile AI event vocabulary over Server-Sent Events and adds `site_patch` events so clients can refresh status mid-turn.
Parameters, scopes and examples
Required scopes
sites.manage
Tenant-bound site-builder message
Request body
{
"site_id": "00000000-0000-4000-8000-000000000001",
"conversation_id": null,
"message": "Make the homepage warmer and highlight workshops.",
"attachment_ids": [
"00000000-0000-4000-8000-000000000002"
]
}
POST/api/v1/admin/sites/attachmentsBearer token
Upload a website-builder attachment
Multipart upload for the Business website builder chat. Requires sites.manage. The file is stored through the shared AI attachment pipeline and later referenced by `attachment_ids` on the site chat route.
Parameters, scopes and examples
Required scopes
sites.manage
DELETE/api/v1/admin/sites/attachmentsBearer token
Delete a pending website-builder attachment
Deletes one tenant-owned, not-yet-bound website-builder attachment before it is sent in chat. Requires sites.manage.
Creates, replaces, or removes the one automatic clips-empty offer for a limited recurring pass or still-valid class pack. The target may be hidden from public catalogs. Permission: passes.manage.
Returns every active venue pass type for authenticated POS staff, including pass types intentionally hidden from public consumer catalogs. Permission: pos.access.
Business-app stream-control DTO for one tenant-bound class instance. Returns source options without provider live-stream ids, stream keys, RTMP URLs, SRT URLs, or playback URLs; action availability includes exact disabled reason codes. Visible to venue schedule/check-in readers and assigned staff roster readers. Source/go-live writes repeat module/settings gates; end remains available for safe live shutdown.
Sets or clears the occurrence-level stream source before the class goes live. Requires class.create, active streaming module/entitlement, a streamable class, an active RTMP/SRT source with an attached provider stream, tenant binding, lifecycle CAS status=scheduled, UUID Idempotency-Key, and no assigned-instructor owner-toggle block. The operation is silent; notification fields are rejected.
Starts a class stream from an existing class provider stream or an active selected RTMP/SRT source. Requires class.create, active streaming entitlement/module, streaming settings enabled, streamable class, venue-local class date, tenant binding, lifecycle CAS status=scheduled, provider-adapter enablement, UUID Idempotency-Key, and no assigned-instructor owner-toggle block. Provider enablement is compensated when the DB transition fails or loses a race unless the winner uses the same stream. The route does not mint new one-time provider streams or expose source credentials; it is operationally silent and rejects notification fields.
Ends a live class stream. Requires class.create, tenant binding, lifecycle CAS status=live, and UUID Idempotency-Key. The class completion commits before the shared-stream provider disable guard runs; the response reports provider_stop as disabled, skipped_shared, failed, or not_applicable. The route records streaming usage after the class completion commit. It is operationally silent and rejects notification fields.
Retries only the provider disable step after a class has already completed; it never re-completes the class or repeats lifecycle effects. Requires class.create, tenant binding, UUID Idempotency-Key, and an attached provider stream. The shared-stream guard is organization-scoped and no blocking occurrence identifier is returned. This route is operationally silent and rejects notification fields.
PHONE-PUBLISH-01: mints an ephemeral, class-scoped provider live stream plus a hashed single-use claim token, bound to one organization, one class occurrence, and the preparing user, with a short server-enforced TTL. Requires class.create OR the assigned instructor when the venue enables instructor go-live, active streaming module/entitlement, streamable class, venue-local class date, the phone_publisher_sessions kill switch, tenant binding, and a UUID Idempotency-Key. Returns non-secret session state and the one-time claim token; NEVER ingest URLs, stream keys, or provider resource ids. One active session per class; supersession refuses while another device is actively publishing with a fresh heartbeat.
PHONE-PUBLISH-01: atomically consumes the single-use claim token and returns short-lived RTMPS ingest material exactly once (Cache-Control: private, no-store). Only the session creator may claim. Deliberately NOT idempotency-cached — a duplicate claim returns CLAIM_ALREADY_USED and the recovery path is revoke + prepare a new session; the old secret is never re-displayed. No ingest material is ever stored server-side.
PHONE-PUBLISH-01: transitions the claimed session to publishing and returns the authoritative session/provider/class status snapshot. Never marks the class live — only the provider active webhook does. Owner-bound, tenant-bound, UUID Idempotency-Key required.
PHONE-PUBLISH-01: periodic liveness touch returning session state, provider connection status (ingest fields stripped), and class lifecycle status. When the provider confirms an active input and the class is still scheduled inside the phone-publisher window, the snapshot reconciles the class to live (CAS; the cron sweep is the backstop). Owner-bound and naturally idempotent, so no Idempotency-Key is required. A stale heartbeat makes a publishing session eligible for takeover by another authorized device.
PHONE-PUBLISH-01: ends the active phone publisher session, completes the class when this session took it live (usage recorded after the completion commit), and records a DURABLE provider-cleanup outcome — a failed teardown is surfaced in GET state and retried, never hidden. Requires class.create or the permitted assigned instructor, tenant binding, and a UUID Idempotency-Key.
PHONE-PUBLISH-01: revokes a session whose device was lost or reinstalled or should no longer publish. The provider stream is disabled and scheduled for deletion, killing any leaked ingest material; a fresh session must be prepared and claimed — the old secret is never re-displayed. Requires class.create or the permitted assigned instructor, tenant binding, and a UUID Idempotency-Key.
PHONE-PUBLISH-01: explicitly retries a failed or pending provider teardown for a terminal publisher session. Requires class.create or the permitted assigned instructor, tenant binding, and a UUID Idempotency-Key.
Parameters, scopes and examples
Required scopes
class.create
Path parameters
classInstanceIdstring · required
Class instance UUID
PATCH/api/v1/admin/schedule/{id}Bearer or API key
Edit class instance
Update start/end time, instructor, class type, capacity, or room on a single class instance. Capacity can never go below the current booked count (422 CAPACITY_BELOW_BOOKED — cancel bookings first; no force override). Instructor/room changes are conflict-checked; instructor must be qualified. Notifications default silent: omitted controls and legacy notify_attendees never send. An explicit notify audience plus channel sends the branded schedule-change email/SMS/push to participants and/or instructors on time/instructor/room changes and requires notifications.send. Idempotency-Key honored; audit_log carries per-field from/to diffs.
Atomic, immutable-ledger correction for an isolated past class. Requires a UUID Idempotency-Key, scheduling.manage_history plus scheduling.manage, expected_updated_at and expected_status for an existing row, a past effective_at, and typed REWRITE attestation. Cancellation-state corrections additionally require class.cancel. Classes with roster, financial, course, workshop, import, streaming, or other linked records fail closed for specialist review. Notifications are always silent.
Parameters, scopes and examples
Required scopes
scheduling.manage_history
Path parameters
idstring · required
Class instance ID
Bounded historical class-instance correction
Request body
{
"operation": "class_instance.correct_timing",
"expected_updated_at": "2026-08-20T09:00:00.000Z",
"expected_status": "completed",
"history_reason": "Signed instructor log confirms the recorded class time",
"history_confirmation_token": "REWRITE",
"effective_at": "2026-08-20T10:00:00.000Z",
"intent": {
"startTime": "2026-08-20T08:00:00.000Z",
"endTime": "2026-08-20T09:00:00.000Z"
}
}
Atomic, immutable-ledger correction for a past recurring availability window. Requires a UUID Idempotency-Key, availability.manage_history, staff_portal.availability, staff.edit for another staff member, expected_updated_at plus expected_is_active for existing rows, a past effective_at, and typed REWRITE attestation. The staff path and tenant-owned row pin ownership. Notifications are always silent.
Applies explicit venue-local start/end time, room, instructor, capacity, or class type to 1–50 tenant-owned classes with per-row conflict/failure results. Notifications default silent; an explicit notify audience plus channel requires notifications.send and sends only after each successful write. Idempotency-Key required.
Cancels 1–50 tenant-owned classes through the canonical cancellation engine with per-row results. Notifications default silent: omission and legacy notify_attendees never send. Explicit notify audience plus channel requires notifications.send; clients support Email/SMS/Push and instructors support Email/SMS. Push without a selected client audience returns 422. Idempotency-Key required.
POST/api/v1/admin/schedule/{id}/cancelBearer or API key
Cancel class
Cancel a class instance (bookings cancelled, clips restored, audit + webhook). Notifications default silent: omission and legacy notify_attendees never send. Explicit notify.{audience,channels} requires notifications.send; channel overrides (email/sms/push) AND with client preferences. Clients support Email/SMS/Push; instructors support Email/SMS, and Push without a selected client audience returns 422. Mixed client+instructor Email/Push notifies clients by Email/Push and instructors by Email. Idempotency-Key honored.
Parameters, scopes and examples
Required scopes
write:schedule
Path parameters
idstring · required
Class instance ID
POST/api/v1/admin/schedule/{id}/substituteBearer or API key
Assign substitute
Replace instructor for a class. Validates no scheduling conflicts across locations. Notifications default silent. Explicit notify audience plus channel requires notifications.send; client delivery is Push-only and substitute-instructor delivery is Email-only; selecting both audiences with Email+Push sends those exact legs. SMS or a channel without its supported audience returns 422. Idempotency-Key honored.
Parameters, scopes and examples
Required scopes
write:schedule
Path parameters
idstring · required
Class instance ID
GET/api/v1/admin/checkinBearer or API key
Venue-local check-in day strip
The venue-local day's classes for the native staff check-in screen (Business app): per-class check-in/waitlist counts, room/instructor, and the day-navigation gates (today vs. read-only past/future). Defaults `date` to the venue-local today when omitted; optional `location_id` (query param or X-Location-ID header) narrows to one location.
Parameters, scopes and examples
Required scopes
read:bookings
Query parameters
datestring
Venue-local date, YYYY-MM-DD. Defaults to the venue-local today.
location_idstring
Restrict results to one location. Also accepted as the X-Location-ID header.
GET/api/v1/admin/checkin/{classInstanceId}Bearer or API key
Attendee list
Class roster with member details, pass info, add-ons, included services, check-in status, and class/booking updated_at concurrency tokens. Whole-class cancellations retain the preserved roster and each attendee’s previous status; ordinary client cancellations remain excluded.
Parameters, scopes and examples
Required scopes
read:bookings
Path parameters
classInstanceIdstring · required
Class instance ID
Query parameters
include_historical_recordsstring
Include protected cancelled/late-cancelled roster rows; requires scheduling.manage_historyDefault: false
Send a bulk email or SMS to a selected subset of one class instance. Submitted booking_ids are intersected server-side with the organization's active or whole-class-preserved roster; ordinary cancellations and stale/foreign ids are dropped and counted as skipped. Caller-supplied contact data is never accepted. Uses the canonical consent/suppression-aware bulk senders and requires the can_view_client_contact_info membership toggle. Idempotency-Key is honored.
Parameters, scopes and examples
Required scopes
members.contact
Path parameters
classInstanceIdstring · required
Class instance UUID
Channel, roster booking ids, and message
Request body
{
"channel": "email",
"booking_ids": [
"00000000-0000-4000-8000-0000000000b1"
],
"subject": "Class update",
"message": "Hi {{first_name}} — here is an update about your class."
}
POST/api/v1/admin/checkin/{classInstanceId}/{bookingId}Bearer or API key
Check in member
Check a member into class. Validates late arrival cutoff.
Parameters, scopes and examples
Required scopes
write:checkin
Path parameters
classInstanceIdstring · required
Class instance ID
bookingIdstring · required
Booking ID
POST/api/v1/admin/checkin/{classInstanceId}/{bookingId}/noshowBearer or API key
Mark no-show
Mark member as no-show. Applies no-show fee if configured.
Parameters, scopes and examples
Required scopes
write:checkin
Path parameters
classInstanceIdstring · required
Class instance ID
bookingIdstring · required
Booking ID
GET/api/v1/admin/membersBearer or API key
List members
Membership-driven client list with exact pre-pagination status and pass filtering. Search by name, email, phone or venue client ID; optionally filter by tag, active pass type, or canonical pass family. pass_type_id and pass_family combine with AND semantics. Every successful response, including zero-match pages, includes meta.pass_type_options and meta.pass_family_options. Options expose distinct active-client counts across the full authenticated venue before pagination; pass types include current active templates plus archived templates still held by active clients, including types hidden from public pricing and course/workshop-managed types.
Parameters, scopes and examples
Required scopes
read:members
Query parameters
searchstring
Search by name, email, or phone
statusstring
Client status: active, inactive, new, or no_pass
tagstring
Filter by member tag
pass_type_idstring
Filter by active pass type
pass_familystring
Filter by pass family: recurring, class_pack, time_based, or intro_offer
Register an active client or send a pending client invitation. Enforces the venue plan limit, requires members.edit and an Idempotency-Key, and records a PII-safe audit event.
Full member profile: passes with course-fulfillment provenance, canonical native course_access, recent bookings/payments, tags, scores, credits, referrals, plus server-authoritative total_bookings and last_visit_at, per-channel notification_availability (email/SMS/push with exact unavailable reasons), and contact_details_visible (contact fields are nulled unless the caller holds members.contact and membership contact visibility).
Soft-deactivates only the active membership at the selected venue; it never deletes the shared profile or changes memberships at other venues. Delivery is silent by default. An explicit notify object may select Email, SMS, and/or Push, which requires notifications.send and an availability preflight before the deactivation commits. A post-commit delivery failure is returned separately as notification_failure and never restores access. Protected Admin/Finance memberships retain their shared lifecycle authorization checks. Idempotency-Key required. Permission: members.delete.
Parameters, scopes and examples
Required scopes
members.delete
Path parameters
idstring · required
Member user ID
Deactivation reason and optional explicit client delivery channels
Tenant-scoped pass history with an exact total and opaque keyset cursor. Returns up to 100 records per page and never exposes processor subscription identifiers.
Deterministically merges live bookings and imported historical visits. Historical rows carry record_source=migration_history and read_only=true. The total is exact across both stores.
Parameters, scopes and examples
Required scopes
members.view_insights
Path parameters
idstring · required
Active member ID
Query parameters
limitinteger
Items per page (1–100)Default: 25
afterstring
Opaque next_cursor from the previous page
pass_idstring
Only bookings funded by this pass
cycle_startstring
Venue-local YYYY-MM-DD start of a pass usage cycle (inclusive)
cycle_endstring
Venue-local YYYY-MM-DD end of a pass usage cycle (exclusive)
Tenant-scoped payments with exact total, refunds, safe card display, invoice linkage, and explicit receipt capabilities. Processor IDs, client secrets, and raw receipt URLs are never returned.
Re-sends through the canonical POS sender to the member contact stored on the server. Only same-venue POS-backed receipt payments are eligible; arbitrary recipients and payment retry are not supported.
Parameters, scopes and examples
Required scopes
notifications.send
Path parameters
idstring · required
Active member ID
paymentIdstring · required
Same-venue payment ID
Receipt delivery channel advertised by the payment receipt capability
Request body
{
"method": "email"
}
GET/api/v1/admin/paymentsBearer token
Org-wide recent sales
Business-app contract C6: the venue's recent payments (all statuses), newest first, mirroring the web sales drawer rows — plain-language method label, card label, money bucket (captured | recorded | internal), and the drawer's refund-offer rule (`refundable` = settled non-guest rows with money remaining). Amounts are integer minor units (øre). Cursor-paginated (opaque keyset cursor), limit ≤ 50. Range resolves in the venue's timezone.
Business-app contract C7: executes a claimed review through canonical processRefund. Body { review_intent_id, confirmation?, amount?, reason?, client_receipt_comment?, destination_id?, method_reference?, notify_client?, receipt_channels?: ('email'|'sms'|'push')[] }. Destination and notes must match the immutable review. Email is selectable (suppression is audited). SMS works only when review context reports available; otherwise execution rejects before money moves with 422 REFUND_SMS_UNAVAILABLE and unavailable_reason. Success includes refund_id, printable bearer-authenticated PDF URL, and per-channel outcomes.
Parameters, scopes and examples
Required scopes
billing.refunds.same_daybilling.refunds.full
Path parameters
idstring · required
Payment UUID
Refund details (amount in MAJOR units)
Request body
{
"review_intent_id": "00000000-0000-4000-8000-000000000000",
"amount": 199,
"reason": "Client requested the refund",
"client_receipt_comment": "We hope to see you again soon.",
"destination_id": "original",
"notify_client": true,
"receipt_channels": [
"email",
"push"
]
}
GET/api/v1/admin/refunds/{id}/receiptBearer token
Download canonical refund receipt PDF
Bearer-authenticated, tenant-scoped, no-store PDF used by native print/share. Contains only the optional client receipt comment; the staff-only internal reason is never rendered.
Business-app contract C8: send a bulk email or SMS to participants of one class instance. Recipients are resolved server-side — the submitted booking_ids are intersected with the class's ACTIVE roster (confirmed/waitlisted/checked_in); stale ids are dropped and counted as skipped, and caller-supplied contact info is never accepted. Delegates to the same senders/consent semantics as the web check-in bulk bar (templates admin_bulk_email / admin_bulk_sms). Requires the TV-D can_view_client_contact_info membership toggle. Returns { sent, skipped }.
Parameters, scopes and examples
Required scopes
members.contact
Path parameters
classInstanceIdstring · required
Class instance UUID
Channel, roster booking ids, and the message
Request body
{
"channel": "email",
"booking_ids": [
"00000000-0000-4000-8000-0000000000b1"
],
"subject": "Tonight’s class moves to Room 2",
"message": "Hi {{first_name}} — we moved tonight’s class to Room 2. See you there!"
}
Business-app parity: the eligible one-class products for paid guest spots. Uses the same guest visitor permission and catalog core as the web check-in screen.
Business-app parity: add 1–20 guest spots as payment-link, paid-at-desk, or comp/free bookings. Payment-link delivery supports email, SMS, or both. Uses the same context-free core as web; Idempotency-Key required.
Parameters, scopes and examples
Required scopes
booking.checkin
Path parameters
classInstanceIdstring · required
Class instance UUID
Guest contact, count, payment mode, product, and delivery channels
Business-app contract C1: the venue's failed payments (payments.status='failed') in the trailing window (default 30 days), newest first, cap 100. Each row carries client + linked pass context, a plain-language method label, and `retryable` per the same pure decider the web Retry button uses. Amounts are integer minor units (øre).
Business-app contract C2: re-collect a failed payment through the canonical retry core (PaymentIntent confirm or off-session invoice pay on the SC2-resolved Connect account, driving handleInvoicePaid). Empty body. Idempotency-Key required. Returns status succeeded | requires_action | failed with a plain-language message.
Record an external settlement for a failed renewal
Business-app contract C3: the failed recurring-renewal invoice was paid through another channel (cash, bank transfer, MobilePay, external card terminal, other). Settles the Stripe invoice out-of-band so the canonical recovery reactivates the pass, attributing the recovered payments row to the real method. amount is integer minor units (øre). Idempotency-Key required.
Parameters, scopes and examples
Required scopes
passes.manage
Path parameters
paymentIdstring · required
Failed payment UUID
Settlement details
Request body
{
"method": "bank_transfer",
"amount": 79900,
"paid_at": "2026-07-31",
"note": "Paid via bank transfer, ref 1234",
"notify_client": true
}
Business-app contract C4: comp the failed recurring-renewal cycle — the client keeps the period, 0 revenue is recorded (the recovered payments row is forced to 'comped' amount 0). Reason required. Idempotency-Key required.
Parameters, scopes and examples
Required scopes
passes.manage
Path parameters
paymentIdstring · required
Failed payment UUID
Waive details
Request body
{
"reason": "Goodwill — studio closure week",
"notify_client": true
}
Business-app contract C5: venue-imposed suspension (distinct from the member freeze) — blocks bookings until unsuspended. Client delivery is silent by default and accepts only notify.audience.clients=true plus an explicit Email/SMS/Push selection; legacy notify_client/notify_channels inputs remain silent. A non-empty selection requires notifications.send, and an unavailable selected channel returns PASS_NOTIFICATION_CHANNEL_UNAVAILABLE before the pass changes. Idempotency-Key (UUID) required; replay returns the stored response and the stable delivery reference prevents re-sending. Delivery failure after the pass write is reported as notification.sent=false and never rolls the suspension back.
Parameters, scopes and examples
Required scopes
passes.manage
Path parameters
passIdstring · required
Pass UUID
Optional reason and explicit, default-silent client notification choice
Business-app contract C5: lift a venue-imposed suspension. Body is optional and silent by default. Client delivery requires notify.audience.clients=true, an explicit Email/SMS/Push selection, and notifications.send; legacy booleans/arrays remain silent. An unavailable selected channel returns PASS_NOTIFICATION_CHANNEL_UNAVAILABLE before the pass changes. Idempotency-Key (UUID) required; replay never re-sends. A post-write delivery failure returns notification.sent=false without rolling the pass change back. 422 NOT_SUSPENDED for a pass that is not suspended.
Business-app contract C5 (PASS-REACTIVATE-01): flip an expired/cancelled NON-recurring pass back to active; a run-out window requires new_end_date ≥ venue-local today. Client delivery is silent by default and requires notify.audience.clients=true, explicit Email/SMS/Push channels, and notifications.send; legacy notification inputs remain silent. Unavailable channels reject before mutation. Idempotency-Key (UUID) required and replay never re-sends; delivery failure after the write returns notification.sent=false without rollback. Recurring memberships are refused (422 RECURRING_UNSUPPORTED) — restart via a real re-mint. Audit pass_reactivated + reverse_payload.
Business POS read for an active venue client. Returns sanitized card references only (brand, last4, expiry, default, expired, chargeable); imported display-only cards are explicitly non-chargeable. Requires the canonical pos.access permission. Never returns customer IDs, processor metadata, full card data, or client secrets.
Business POS card-setup operation for an active venue client. Requires an in-person consent attestation and Idempotency-Key. Returns the SetupIntent client secret, exact Stripe account namespace, legal merchant country, and frozen regional revision for native Payment Sheet.
Update the member phone number after an explicit staff confirmation. Requires members.edit and writes an audit record.
Parameters, scopes and examples
Required scopes
write:members
Path parameters
idstring · required
Member user ID
Supported member profile fields
Request body
{
"phone": "+4512345678"
}
POST/api/v1/admin/members/{id}/creditsBearer or API key
Issue account credit
Grant account credit to an active member (positive manual adjustment) on the same atomic, organization-scoped ledger path as the web action. The response balance is the canonical venue-available balance; profiles.credit_balance is maintained only as an account-wide compatibility cache. Currency must equal the venue currency (422 CURRENCY_MISMATCH). Client delivery is silent by default and requires an explicit canonical Email/SMS/Push selection plus notifications.send; membership and unavailable selected channels are rejected before the balance changes, and legacy booleans remain silent. Idempotency-Key is required (1–255 characters): an identical retry returns the original transaction and balance, while reuse for a different semantic request returns 409 IDEMPOTENCY_KEY_REUSE_MISMATCH.
Venue-wide booking list with filtering by date, status, class, member, and location.
Parameters, scopes and examples
Required scopes
read:bookings
Query parameters
fromstring
Start date (YYYY-MM-DD)
tostring
End date (YYYY-MM-DD)
statusstring
Filter by booking status
class_instance_idstring
Filter by class instance
user_idstring
Filter by member
location_idstring
Filter by location
POST/api/v1/admin/bookingsBearer or API key
Book for member
Create a confirmed or waitlisted booking on behalf of a member. Supports capacity override for admins. Client delivery is silent by default and requires an explicit Email/SMS/Push selection plus notifications.send; unavailable selected channels are rejected before booking/pass/count effects. The engine automatic notice is suppressed for this admin route so omission cannot send.
POST/api/v1/admin/bookings/waitlistBearer or API key
Add member to waitlist
Manually place a member on a class's waitlist at the queue tail. Always creates a waitlisted booking (never auto-confirms). Client delivery is default-silent and requires both an explicit client audience/channel selection and notifications.send; unavailable selected channels are rejected before queue effects.
DELETE/api/v1/admin/bookings/waitlist/{bookingId}Bearer or API key
Remove member from waitlist
Remove a waitlisted booking. Waitlisted rows only (409 on a confirmed booking); never triggers auto-promotion. Idempotent. Client delivery is default-silent and requires both an explicit client audience/channel selection and notifications.send; unavailable selected channels are rejected before queue effects.
Parameters, scopes and examples
Required scopes
write:bookings
Path parameters
bookingIdstring · required
Waitlisted booking ID
Optional reason and explicit client notification channels. Omit notify to stay silent.
POST/api/v1/admin/bookings/{bookingId}/cancelBearer or API key
Cancel a confirmed booking
Cancel a member's confirmed booking on their behalf (admin cancel semantics — may charge late fees + restore clips per policy; NOT the fee-free lapsed-booking path). Decrements booked_count, writes audit + booking.cancelled webhook, and issues a 30s undo ticket. Client delivery is silent by default and requires an explicit Email/SMS/Push selection plus notifications.send; unavailable selected channels are rejected before any mutation; legacy notify_client remains silent. Idempotent via Idempotency-Key. Returns 409 ALREADY_CANCELLED on a cancelled booking and 409 ON_WAITLIST for a waitlisted row (use the waitlist remove endpoint).
Bearer-JWT only. Correct one past class booking through the protected, organization-scoped historical ledger. Requires scheduling.manage_history plus the ordinary operation permission (bookings.manage for retrocreate, booking.checkin for attendance, booking.checkin + bookings.mark_no_show for no-show, or booking.cancel_member for cancellation/invalidation). Idempotency-Key must be a UUID. expected_class_updated_at is a compare-and-set token mandatory for every operation; expected_updated_at is a compare-and-set token additionally required for existing-booking operations. The executor refuses linked financial, pass, guest, waitlist, external, and other unsafe effects rather than inventing compensating semantics. Historical correction delivery is explicitly default-silent: Email, SMS, and Push are not available for this operation; a canonical explicit selection first requires notifications.send and then returns 422 before any mutation. Until the protected database executor has been installed, the route returns 503 HISTORICAL_EXECUTOR_UNAVAILABLE and never substitutes table calls.
Parameters, scopes and examples
Required scopes
scheduling.manage_history
Path parameters
bookingIdstring · required
Class booking ID
One closed class-booking correction. Every operation requires expected_class_updated_at; existing-booking operations also require expected_updated_at. history_confirmation_token must be REWRITE.
Bearer-JWT, passes.manage-scoped server-authoritative preview for a recurring membership. Resolves the selected client and saved card in the active venue, validates the venue-local start-date policy, and returns canonical buyer-specific gross pricing, registration fee/waiver, due-today amount, access date, first charge, next renewal, card label, contract/terms summary, and — when an operator discount schedule is requested — the resolved discount_schedule block with the agreed amount, the number of discounted periods and the first full-price charge date. This endpoint never mutates or charges.
Parameters, scopes and examples
Required scopes
passes.manage
Recurring membership options with exactly one of saved_payment_method_id (card-collected) or external_tender_method (venue-collected renewals, billing_mode=external). Optional registration_fee_discount applies a per-sale percentage discount to the one-time registration fee; legacy waive_registration_fee remains accepted. Optional discount_schedule sets an operator-agreed price for the first period, a fixed number of periods, or for as long as the membership runs.
Bearer-JWT, passes.manage-scoped recurring membership creation through the canonical subscription checkout core. Idempotency-Key is required. Re-resolves pricing, dates, saved-card ownership, Stripe locality, VAT/age band, concessions, and legal delivery before mutation. Returns the exact preview plus pass/subscription ids, payment status, and contract-delivery result. Off-session declines and SCA requirements are explicit 402 responses.
Parameters, scopes and examples
Required scopes
passes.manage
The same server-authoritative options accepted by the preview endpoint
Bearer-JWT, passes.manage-scoped option list for an organization-owned pass. Each option is buyer-priced by the canonical membership-change quote engine; a failed target is reported separately and cannot hide valid sibling options. Query: pass_id.
Parameters, scopes and examples
Required scopes
passes.manage
GET/api/v1/admin/memberships/changeBearer token
Preview a client membership change
Bearer-JWT, passes.manage-scoped server quote. Query: pass_id, target_pass_type_id and optional override_price_major. Returns exact charge, credit, effective date, next renewal and a short-lived signed quote binding; it never mutates or charges.
Parameters, scopes and examples
Required scopes
passes.manage
POST/api/v1/admin/memberships/changeBearer token
Apply a client membership change
Bearer-JWT, passes.manage-scoped confirmation through the canonical membership-change core. Requires Idempotency-Key and the exact signed quote returned by preview; foreign-venue passes resolve as not found and client-supplied prices are not accepted.
Process an idempotent point-of-sale transaction. Supports cash, venue credit, and a server-validated saved card. Saved-card SCA returns a 202 challenge response and is completed with a separate idempotent finalize request. Fresh cards, MobilePay and Stripe Terminal use their dedicated flows.
Recent POS transactions filtered by location and date. Refund headroom subtracts both succeeded and in-flight operation claims; refunded_amount reports succeeded claims and pending_refund_amount reports the reserved in-flight amount.
Parameters, scopes and examples
Required scopes
read:payments
POST/api/v1/admin/pos/transactions/{id}/receiptBearer or API key
Resend POS receipt
Resend a tenant-scoped POS transaction receipt by email or SMS. Uses the client's stored contact unless an explicit recipient is supplied. Idempotency-Key is required and retries of the same delivery action must reuse it.
Parameters, scopes and examples
Required scopes
write:pos
Path parameters
idstring · required
POS transaction ID
Receipt delivery channel and optional recipient override
Request body
{
"method": "email"
}
GET/api/v1/admin/pos/summaryBearer or API key
Daily POS sales summary
Daily sales breakdown for the given date (default today): totals (gross/discounts/VAT/credits/net) plus per-payment-method and per-transaction-type buckets. Completed transactions only; same date-window semantics as /admin/pos/recent.
Parameters, scopes and examples
Required scopes
read:payments
Query parameters
datestring
YYYY-MM-DD (default today)
location_idstring
Filter by location
GET/api/v1/admin/dashboard/revenue-seriesBearer or API key
Daily revenue series (sparkline)
Zero-filled daily revenue series ending today — succeeded payments bucketed by UTC day, matching the dashboard revenue_today semantics. days clamps to 1–90 (mobile uses 7 and 30).
Parameters, scopes and examples
Required scopes
read:reports
Query parameters
daysinteger
Window length in days (1–90)Default: 7
POST/api/v1/admin/members/{id}/membership/pauseBearer or API key
Pause membership
Pause (freeze) a member’s pass for a date window. Validated against the pass type’s pause policy; recurring memberships receive exact per-cycle billing credits on their own Stripe account; audit_log pass_paused. Client delivery is silent by default and requires notify.audience.clients=true plus explicit Email/SMS/Push channels and notifications.send. Legacy notification booleans remain silent. Selected-channel availability is rechecked before mutation; exact unavailable/preflight-failed responses leave the membership unchanged. Idempotency-Key honored. {id} accepts UUID or display ID (e.g. HYC-0042).
POST/api/v1/admin/members/{id}/membership/resumeBearer or API key
Resume membership
Resume a paused pass (Stripe-first ordering with compensating re-pause). Audit_log pass_resumed. Client delivery is silent by default and uses only an explicit canonical Email/SMS/Push selection. Selected-channel availability is rechecked before mutation; exact unavailable/preflight-failed responses leave the membership unchanged. Idempotency-Key honored.
Parameters, scopes and examples
Required scopes
write:members
Path parameters
idstring · required
Member user ID or display ID
Resume immediately or from a venue-local date. An unproven Stripe pause stays blocked unless acknowledge_unproven_pause types CLEAR PAUSE plus a reason. Optional explicit client delivery.
POST/api/v1/admin/members/{id}/membership/terminateBearer or API key
Cancel / terminate membership
Cancel or terminate a recurring membership with explicit effective dates: mode period_end (cancel at current cycle end), chosen_cycle (kth upcoming cycle, cycle required), or immediate. Runs the kill-switch-gated termination engine (fail-closed Stripe). Response carries the engine-confirmed effective_at. Client delivery is silent by default and requires an explicit canonical channel choice plus notifications.send; legacy booleans remain silent. Selected-channel availability is rechecked before mutation; exact unavailable/preflight-failed responses leave the membership unchanged. Idempotency-Key honored.
GET/api/v1/admin/members/{id}/membership/termination-previewBearer or API key
Termination preview (cycle picker)
Next 6 cycle boundaries (effective_at, venue-local last usable day, precedes-binding flag), venue policy defaults, and billing horizon for the terminate endpoint’s cycle picker.
Parameters, scopes and examples
Required scopes
read:members
Path parameters
idstring · required
Member user ID or display ID
Query parameters
pass_idstring
Pass ID (uuid)
POST/api/v1/admin/terminal/connection-tokenBearer or API key
Stripe Terminal connection token
Mint a Stripe Terminal connection token plus the venue Terminal location id (`{secret, location_id}`) for card-present readers and Tap-to-Pay. Ephemeral-token fetch — no Idempotency-Key (the Terminal SDK always needs a fresh token).
Parameters, scopes and examples
Required scopes
write:pos
POST/api/v1/admin/terminal/payment-intentBearer or API key
Create Terminal payment intent
Create a card-present PaymentIntent (manual capture) on the venue connected account. Returns `{client_secret, payment_intent_id}`. Money mutation — send an Idempotency-Key; replays return the cached response and the key is forwarded to Stripe.
Parameters, scopes and examples
Required scopes
write:pos
Payment intent
Request body
{
"amount": 12000,
"currency": "DKK"
}
POST/api/v1/admin/terminal/captureBearer or API key
Capture Terminal payment
Capture a confirmed card-present PaymentIntent. Returns `{captured: true, payment_intent_id}`. Money mutation — send an Idempotency-Key; an already-captured intent returns success.
Parameters, scopes and examples
Required scopes
write:pos
Capture
Request body
{
"payment_intent_id": "pi_xxx"
}
POST/api/v1/admin/terminal/receiptBearer or API key
Send Terminal receipt
Email or SMS a receipt for a captured Tap-to-Pay sale, resolved from the Stripe payment intent id. TERM-IDEMP-01: requires a caller-scoped Idempotency-Key; a replayed key returns the cached terminal response instead of re-sending.
POST/api/v1/admin/notifications/broadcastBearer or API key
Send broadcast
Send one or more push, email, and SMS channels to all members, selected member ids, or a server-resolved tag/pass/class audience. Idempotency-Key is required. Each channel derives a stable per-recipient delivery reference; a partial retry skips terminal successes/suppressions and resumes failed legs. Returns sent/skipped/failed counts per channel.
Parameters, scopes and examples
Required scopes
write:notifications
Broadcast
Request body
{
"channels": [
"email",
"sms"
],
"title": "New class added",
"target": {
"type": "tag",
"tag": "vip"
},
"subject": "New class added",
"body": "Check out our new Hot Power class on Saturday!"
}
GET/api/v1/admin/notifications/recentBearer or API key
Recent notifications
Recent email, SMS, and push notifications sent by the venue.
Parameters, scopes and examples
Required scopes
read:notifications
POST/api/v1/admin/staff/inviteBearer token
Invite a staff member
PROMPT_02 (S1-03) — provisions the auth user + profile + membership (status=invited), mints a staff_invitations claim token, and emails the venue-branded /auth/claim-invite link. Permission: staff.manage. The token is consumed by the WEB claim page (set password → membership flips invited→active); there is no separate accept API endpoint because the claim sets a password. 409 EMAIL_EXISTS when a Booking Bible account already exists for the email (adding an existing user as staff is a role change — use the admin UI). location_ids is stored on the invitation for record-keeping; location assignment remains a post-onboarding admin action. Emits staff.invited. Idempotency-Key supported.
Every staff shift in the venue for a date range. Permission: staff_scheduling.view. Joins staff profile name. Optional ?status= filter.
Parameters, scopes and examples
Query parameters
fromstring
Start ISO datetimeDefault: -7 days
tostring
End ISO datetimeDefault: +14 days
statusstring
Filter by ShiftStatus
POST/api/v1/admin/staff-scheduleBearer token
Create a staff shift
Create a new shift. Permission: staff_scheduling.manage. Note: API path skips the engine compliance pre-checks; for full compliance use the admin panel or the createShift server action.
POST/api/v1/admin/walk-in-queue/{id}/callBearer or API key
Call queue entry
Mark a queue entry as called and notify the client by SMS if they opted in. Permission: bookings.manage.
Parameters, scopes and examples
Required scopes
write:bookings
Path parameters
idstring · required
Queue entry ID
DELETE/api/v1/admin/walk-in-queue/{id}Bearer or API key
Remove walk-in
Cancel/remove a walk-in queue entry. Permission: bookings.manage.
Parameters, scopes and examples
Required scopes
write:bookings
Path parameters
idstring · required
Queue entry ID
GET/api/v1/admin/checkin/{classInstanceId}/qr-tokenBearer or API key
Get check-in QR token
Returns the current rotating QR token for a class instance. A new token is generated if none exists or the existing one is expired. Force rotation with ?refresh=true. Token TTL: 5 minutes. Permission: booking.checkin.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
GET/api/v1/admin/rates/distributionBearer or API key
Get revenue distribution by rate
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication. The client and pass type must both belong to that venue.
Accepts exactly one credential: Bearer JWT with `rates.override`, or an API key bound to the venue with `write:passes`. Dual credentials are rejected before authentication.
DELETE/api/v1/admin/rates/override/{passId}Bearer or API key
Clear a pass rate override
Accepts exactly one credential: Bearer JWT with `rates.override`, or an API key bound to the venue with `write:passes`. Dual credentials are rejected before authentication.
Parameters, scopes and examples
Required scopes
write:passes
Path parameters
passIdstring · required
Pass id
Response example
{
"data": {
"ok": true
},
"error": null
}
GET/api/v1/admin/private-eventsBearer or API key
List private-event bookings
Accepts exactly one credential: Bearer JWT with `private_events.view`, or an API key bound to the venue with `read:private_events`. Targets are non-enumerating and venue-scoped.
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
Parameters, scopes and examples
Required scopes
write:private_events
Private-event booking. Every PS-B2 field below is OPTIONAL and additive: client_id / save_as_client (link or create the client the session is for), partner_id + billing_target/billing_address/billing_vat_number/po_number/department/cost_center (bill a company — the billing block prefills from the partner record), brand_id, location_id, staff_note (a message the client sees), pricing_override ({mode: per_person|total, amount} — total is VAT-inclusive), and start_mode (confirmed | inquiry | confirm_on_payment) with payment_due_at. The legacy `status` field keeps working.
GET/api/v1/admin/private-events/{id}Bearer or API key
Get a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.view`, or an API key bound to the venue with `read:private_events`. Targets are non-enumerating and venue-scoped.
PATCH/api/v1/admin/private-events/{id}Bearer or API key
Update a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
Parameters, scopes and examples
Required scopes
write:private_events
Path parameters
idstring · required
Booking id
Fields to update. PS-B2 adds the same optional fields the create route takes (client_id, partner_id + billing block, brand_id, location_id, staff_note, pricing_override, payment_due_at) plus `reprice` (recompute the frozen subtotal/VAT/total/deposit) and `notify_client` ({enabled, channels}). The response carries the client-visible change summary.
POST/api/v1/admin/private-events/{id}/approveBearer or API key
Approve a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
POST/api/v1/admin/private-events/{id}/cancelBearer or API key
Cancel a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
POST/api/v1/admin/private-events/{id}/quoteBearer or API key
Send a private-event quote
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
Accepts exactly one credential: Bearer JWT with `loyalty_price.manage`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
POST/api/v1/admin/loyalty-price/grantBearer or API key
Give a client the loyalty price
Accepts exactly one credential: Bearer JWT with `loyalty_price.grant`, or an API key bound to the venue with `write:passes`. Writes through the context-free grant core (never a cookie action), so the audit trail and status recompute are identical to the admin web surface.
Parameters, scopes and examples
Required scopes
write:passes
user_id + a short reason. Optional venue-local expiry, and an optional pass_id with an agreed price on the catalog (MAJOR) scale — pass_price_override requires pass_id.
Request body
{
"user_id": "uuid",
"reason": "Agreed with the owner at the desk",
"expires_on": "2027-01-31",
"pass_id": "uuid",
"pass_price_override": 249
}
List every event on the unified calendar (classes, appointments, private events, streams, blocked time, instructor unavailability, blackouts, room rentals, maintenance, staff shifts, open gym) in a date range. JWT (any staff role) returns the org feed; API key with read:calendar returns the same. Filters: room_id, staff_id, location_id, brand_id, sources (comma-separated), only_blocking.
List maintenance slots in a date range. API key with read:maintenance scope. Filters: start, end (ISO datetime), room_id, status, limit (1-200, default 50).
Create a maintenance slot. API key with write:maintenance. Body: maintenance_type (preventive | corrective | inspection | deep_clean | equipment | renovation), title, start_time, end_time, plus optional priority, room_id, equipment_id, blocks_room (default true), assigned_staff_id, vendor_name, vendor_contact, estimated_cost, notes. Idempotency-Key header honored. When blocks_room is true and a room is set, conflicts against classes / appointments / private events / streams / room rentals / other maintenance return 409 with the conflict list. Emits maintenance.scheduled.
Parameters, scopes and examples
Required scopes
write:maintenance
Maintenance creation payload
Request body
{
"maintenance_type": "deep_clean",
"title": "Quarterly studio deep clean",
"start_time": "2026-05-01T20:00:00Z",
"end_time": "2026-05-01T22:00:00Z",
"room_id": "uuid",
"priority": "normal",
"blocks_room": true
}
Staff33 documented operations
GET/api/v1/staff/scheduleBearer token
My teaching schedule
Instructor's classes. Optional scope=own|partner|all; every row includes origin venue metadata and origin.timezone so apps bucket collaboration classes in the owning venue's local day.
GET/api/v1/staff/earningsBearer token
My earnings
Compensation, tips, and commissions broken down by period and class. tips_settled_via_collaboration is additive visibility for gratuities paid on a practitioner statement and is deliberately excluded from tips_received and total.
GET/api/v1/staff/classes/{id}/rosterBearer token
Class roster
View attendee list for a class the instructor is assigned to. Returns class and booking updated_at CAS tokens, venue-local day_state, and historical_capabilities. include_historical_records=true additionally exposes terminal roster rows and requires scheduling.manage_history.
Business-app staff correction using the same atomic ledger as Admin. Requires an active venue, roster access, class assignment where applicable, scheduling.manage_history, and the ordinary operation permission. Every operation requires expected_class_updated_at; existing rows also require expected_updated_at. Delivery is default-silent.
Parameters, scopes and examples
Path parameters
idstring · required
Class instance ID
bookingIdstring · required
Class booking ID
Bounded historical roster correction with UUID Idempotency-Key
Provider-scoped atomic correction for an isolated past class. The active provider must be assigned to the existing class; retrocreate must assign that provider directly, and assignment corrections must retain them. Requires schedule.view_own, scheduling.manage_history, scheduling.manage, UUID Idempotency-Key, CAS evidence for existing rows, past effective_at, and typed REWRITE. Notifications are always silent.
Mark or unmark a participant present for a course session ({user_id, present}). Idempotent; writes the same attendance store the web roster uses. Supports Idempotency-Key.
Send an email or SMS to course participants (audiences: enrolled, waitlisted, all, by track, by payment status, hand-picked). Requires course-manage scope; rate-limited; supports Idempotency-Key (retries never double-send).
Parameters, scopes and examples
Path parameters
idstring · required
Course ID
Message
Request body
{
"channel": "email",
"subject": "Bring a mat tomorrow",
"message": "Hi everyone — please bring your own mat to tomorrow’s session.",
"audience": {
"kind": "enrolled"
}
}
GET/api/v1/staff/availabilityBearer token
List my unavailable dates
Calling staff member's current and future unavailable dates for the selected venue. Permission: staff_portal.availability.
POST/api/v1/staff/availabilityBearer token
Set availability
Add or update unavailable dates for the calling staff member. Permission: staff_portal.availability.
Strict partial update of a current/future window using the exact updated_at token returned by GET. Caller must own the window; another instructor requires staff.edit. A stale token returns 409 STALE_TARGET. Existing or target ranges touching venue-local history fail closed until the dedicated executor is installed.
Parameters, scopes and examples
Path parameters
idstring · required
Window ID
Concurrency token plus one or more changed window fields
Sets is_active=false on a current/future window using the exact updated_at token returned by GET, after tenant and owner-or-staff.edit authorization. A stale token returns 409 STALE_TARGET. Historical ranges fail closed until the dedicated executor is installed.
Atomic, immutable-ledger correction for a past recurring availability window owned by the active staff member. Requires availability.manage_history, staff_portal.availability, UUID Idempotency-Key, expected_updated_at plus expected_is_active for existing rows, a past effective_at, and typed REWRITE. Notifications are always silent.
Parameters, scopes and examples
Path parameters
idstring · required
Availability window ID
Self-owned historical availability correction
Request body
{
"operation": "availability_window.invalidate",
"expected_updated_at": "2026-08-20T09:00:00.000Z",
"expected_is_active": true,
"history_reason": "Approved rota confirms that this window did not apply",
"history_confirmation_token": "REWRITE",
"effective_at": "2026-08-10T10:00:00.000Z",
"intent": {}
}
GET/api/v1/staff/substitute-poolBearer token
Read substitute-pool opt-in
Returns { enabled, updated_at } for the calling user's active org.
PUT/api/v1/staff/substitute-poolBearer token
Toggle substitute-pool opt-in
Set whether the calling user is available to be auto-suggested as a substitute. Body: { enabled: boolean }. Emits substitute_pool.opt_in_changed.
Parameters, scopes and examples
Opt-in state
Request body
{
"enabled": true
}
GET/api/v1/staff/appointmentsBearer token
My appointments
Cursor-paginated list of the calling provider's appointments, including venue currency and the same client name and 80-character provider-note preview shown in the web staff list. Contact details are not exposed. Query params: cursor (opaque next_cursor; legacy ISO timestamps are temporarily accepted), limit (1..100, default 25), status (one of the appointment status strings), direction (upcoming|past, default upcoming).
Parameters, scopes and examples
Query parameters
cursorstring
Opaque next_cursor returned by the previous page
limitnumber
Page size (1..100)Default: 25
statusstring
Optional status filter
directionstring
upcoming | pastDefault: upcoming
GET/api/v1/staff/appointments/{id}Bearer token
My assigned appointment detail
Provider-scoped detail with updated_at CAS evidence, server-authoritative historical review flags, privacy-gated client contact fields, and exact per-channel notification availability. The route always binds provider_id to the caller.
PATCH/api/v1/staff/appointments/{id}Bearer token
Act on my assigned appointment
Provider-scoped check_in, start, complete, no_show, cancel, or reschedule. Requires the action-specific appointments.*_own permission, exact expected_updated_at, and Idempotency-Key. Client notifications are default-silent and require explicit notification_channels plus notifications.send and server preflight. Past/terminal mutations fail closed until the appointment historical executor is installed.
Parameters, scopes and examples
Exact provider lifecycle intent and caller-rendered concurrency snapshot
Provider-scoped form of the dedicated atomic appointment-history command. Requires staff_portal.appointments, appointments.manage_history, the ordinary operation permission, a UUID Idempotency-Key, REWRITE attestation, and exact expected_updated_at plus expected_status CAS for existing rows. The existing appointment and any retrocreate or assignment target must remain assigned to the active provider. Corrections are always silent. Returns 503 HISTORICAL_EXECUTOR_UNAVAILABLE without table-call fallback until correct_appointment_historical is installed.
Parameters, scopes and examples
Required scopes
appointments.manage_history
Path parameters
idstring · required
Appointment UUID
The same closed appointment correction body as the admin route
Calling staff member's own non-instructor shifts (reception, cleaning, manager, front desk) in a date range. Use ?from=&to= ISO datetimes; defaults to next 14 days.
Parameters, scopes and examples
Query parameters
fromstring
Start ISO datetimeDefault: now
tostring
End ISO datetimeDefault: +14 days
POST/api/v1/staff/shifts/clock-inBearer token
Clock in
Clock in to an own staff shift. Allowed from 15 min before scheduled start through 30 min after. Sets status to in_progress and stamps clock_in_at. Emits shift.clock_in.
Parameters, scopes and examples
Shift to clock in to
Request body
{
"shift_id": "uuid"
}
POST/api/v1/staff/shiftsAPI key
Create a staff shift
Create a non-instructor staff shift. API-key only (write:staff). Body: start_time, end_time, optional staff_id, shift_type (regular | overtime | on_call | training | meeting), break_minutes, role_required, location_id, hourly_rate, notes. Idempotency-Key header honored. Emits shift.created (and shift.assigned if a staff_id is set).
Soft-cancel a shift (sets status=cancelled, preserves audit/payroll references). JWT (admin/manager) or API key with write:staff. Use ?reason= to attach a cancellation reason to the audit row.
Parameters, scopes and examples
Required scopes
write:staff
Path parameters
idstring · required
Shift UUID
Query parameters
reasonstring
Cancellation reason (free text)
POST/api/v1/staff/clockBearer token
Clock in or out (unified)
Unified clock-in/out endpoint. JWT only — resolves the staff member from the session token. Body: { action: "in" | "out", shift_id }. On clock-out the response includes actual_hours and total_pay. Emits shift.clock_in or shift.clock_out.
Parameters, scopes and examples
Clock action
Request body
{
"action": "in",
"shift_id": "uuid"
}
POST/api/v1/staff/shifts/clock-outBearer token
Clock out
Clock out of an in-progress staff shift. Computes actual_hours, actual_break_minutes, and total_pay (when hourly_rate is set). Returns warnings for break/EU compliance issues. Emits shift.clock_out.
Parameters, scopes and examples
Shift to clock out of
Request body
{
"shift_id": "uuid"
}
GET/api/v1/staff/time-offBearer token
My time-off requests
Latest 100 own time-off requests across all statuses.
POST/api/v1/staff/time-offBearer token
Request time off
Submit a new time-off request. Always created with status=pending. Manager approval/decline happens via the admin panel. Emits time_off.requested.
Create or update a lead for the venue. Public rate-limited (10 req/min/IP) or API-key authenticated (write:leads). Upserts on (organization_id, email): provided fields populate blanks, existing non-null values are preserved. Fires the lead_captured analytics event and emits a lead.created webhook with the full record plus an attribution object (utm_*, fbclid, gclid, landing_page, referrer).
Parameters, scopes and examples
Required scopes
write:leads
Lead payload. Org resolves from API key > X-Organization-ID header > subdomain > organization_id.
List leads for the API key's organization. API key only (JWT not permitted). Requires the read:leads scope.
Parameters, scopes and examples
Required scopes
read:leads
Query parameters
searchstring
Search by email, first_name, or last_name
sourcestring
Filter by source (website_form, exit_intent, referral, etc.)
statusstring
Filter by status (new, contacted, converted, unsubscribed)
pageinteger
Page numberDefault: 1
limitinteger
Items per page (max 100)Default: 20
Events3 documented operations
POST/api/v1/eventsPublic
Track an analytics event
Record a server-side analytics event into user_events. Public rate-limited (60 req/min/IP) or API-key authenticated (write:events). For conversion event names (purchase, subscribe, refund, lead_captured) we additionally fire Meta CAPI + GA4 MP when the venue has pixel credentials configured.
Parameters, scopes and examples
Required scopes
write:events
Event payload. UTM + click-id + page URL get merged into event_properties.
Create an open-gym session for a client. Validates an active pass with allow_open_gym=true and the access schedule. JWT users self-check in; API keys must include user_id.
Parameters, scopes and examples
Required scopes
write:bookings
Optional location, source, pass override, and notes.
Returns the latest version of each active required waiver for the authenticated client in the validated X-Organization-ID venue, including the exact markdown body to display and the latest version the client signed. `body_md` is canonical; `body` is the native-app compatibility alias with the same value.
Removes the caller's own club membership. Idempotency-Key supported; leaving a club you are not in is a no-op success. Emits club.member_left (audit + webhook).
Parameters, scopes and examples
Path parameters
idstring · required
Club id
Response example
{
"data": {
"ok": true
},
"error": null
}
DELETE/api/v1/clubs/{id}/membershipBearer or API key
Leave a club (membership alias)
REST-shaped alias for POST /clubs/{id}/leave used by the mobile clubs contract — identical behavior (Idempotency-Key, no-op success when not a member, club.member_left emit).
Parameters, scopes and examples
Path parameters
idstring · required
Club id
Response example
{
"data": {
"ok": true
},
"error": null
}
GET/api/v1/clubs/suggestionsBearer or API key
List club suggestions (admin)
Admin queue of client-submitted club suggestions. Filter by status.
Returns a single chat channel summary (channel row + unread_count + last_message_at) for the authenticated org. Staff role (or chat.read scope) required.
Bulk Scan Session — map a single scanned barcode to a preset target
Hot-path endpoint for the rapid-mapping Bulk Scan Session. Each call maps one scanned barcode. Returns status=created (new mapping), duplicate_in_session (same barcode+target already exists), requires_confirmation (different target, resend with allow_overwrite=true to proceed), or overwritten.
Model Context Protocol server (HTTP transport, JSON-RPC 2.0, protocol 2025-03-26). Authenticate with `X-API-Key`. Methods: `initialize`, `ping`, `resources/list`, `resources/read`, `tools/list`, `tools/call`. Read-only in v1. See `/developers/mcp` for the full guide.
Returns every registered feature module with its resolved enabled/settings/source for the calling venue. Resolution honors the four-tier precedence (tenant override → group lock → venue → group default → plan → default). Mobile Business app uses this for parity with /admin/settings/features.
Parameters, scopes and examples
Response example
{
"data": [
{
"key": "leaderboards",
"label": "Leaderboards",
"description": "Member-facing leaderboards by class type, period, and metric.",
"category": "Community",
"enabled": true,
"source": "plan",
"locked_by_group": false,
"settings": {}
}
]
}
PATCH/api/v1/admin/features/[moduleKey]Bearer or API key
Update a venue-level feature toggle
Flip enabled/settings for a feature module at the venue tier. Idempotency-Key supported. Returns 400 with `Locked by group: <paths>` when the venue tries to flip a group-locked toggle or write to a group-locked dot-path in `settings`. Audit-logged + emits `feature_toggle.changed` webhook.
Parameters, scopes and examples
Required scopes
write:settings
Path parameters
moduleKeystring · required
Module key from feature_modules.key
Partial update — only the fields you want to change.
Browse partner venues available to the member across the BOOKING BIBLE network. Each entry exposes a public summary plus the exact relationship status, active partnership id, and venue-level bookable flag for the organization selected by X-Organization-ID. Member-JWT.
Book a class at a partner venue using a network-eligible pass. Resolves the legal gate against the HOST venue’s documents before booking. Requires a caller-stable `Idempotency-Key` header; exact retries return the original booking and visit. Member-JWT.
Creates a venue-to-venue Network partnership request through the context-free Network mutation core. Bearer JWT requires network.manage; API keys require write:network.
GET/api/v1/network/partnerships/{id}Bearer or API key
Read a venue Network partnership
Reads one venue-to-venue Network partnership after proving the caller belongs to either party. Bearer JWT requires network.view; API keys require read:network.
PATCH/api/v1/network/partnerships/{id}Bearer or API key
Update a venue Network partnership
Updates a venue-to-venue Network partnership through the commercial lifecycle. Bearer JWT requires network.manage. API keys with write:network may change lifecycle status, but agreement negotiation and terms revisions require a verified human JWT administrator and return 403 for API-key callers.
DELETE/api/v1/network/partnerships/{id}Bearer or API key
Terminate a venue Network partnership
Terminates immediately only when binding and notice have both elapsed; otherwise schedules termination through the locked service RPC. Bearer JWT requires network.manage; API keys require write:network.
GET/api/v1/network/partnerships/{id}/visitsBearer or API key
List visits for a venue Network partnership
Lists visit ledger rows for one venue-to-venue Network partnership after proving the caller belongs to either party. Bearer JWT requires network.view; API keys require read:network.
GET/api/v1/network/partnerships/{id}/settlementsBearer or API key
List settlements for a venue Network partnership
Lists network-only settlements for one venue-to-venue Network partnership after proving the caller belongs to either party. Bearer JWT requires network.view; API keys require read:network.
Lists collaborations for the workspace selected by X-Organization-ID. Returns venue-owned relationships and invitations received by an owned professional workspace. Supplying the exact email query performs the privacy-preserving invitation lookup and requires network.manage.
Creates a pending venue-to-professional collaboration with an explicit venue role and compensation model. Requires network.manage and a non-individual venue workspace.
Accepts or declines an invitation from the professional workspace, or lets the venue set role, pause, resume, or terminate the relationship. Every operation is tenant-checked and requires network.manage.
Ends the relationship through the canonical termination core and suspends its venue membership unless keep_membership is explicitly true. Either party may terminate; requires network.manage.
Parameters, scopes and examples
Optional termination reason and membership handling
List the caller’s relationships (bidirectional — both relationships the member created and ones pointing back at them), hydrated with the linked member’s profile. Unlocks family pricing, shared booking, and pass sharing. Member-JWT, org-scoped.
Add a relationship. When `related_email` matches a member in the same venue, the relationship links to their profile and a mirror row is written so both members see it. Member-JWT. Idempotency-Key supported.
Submit a private-event inquiry as the authenticated member. Validates participant count against the event type’s min/max, computes pricing, and inserts a `private_event_bookings` row with `booked_by` set; emits `private_event.inquiry_created`. Member-JWT, org from X-Organization-ID. Idempotency-Key supported.
PROMPT_11 — returns the Stripe `client_secret`, frozen `merchant_country_code`, and `stripe_account_id` (`acct_*` for a direct Connect PI, otherwise null) for the booking’s deposit/full charge so the member can initialize Stripe Elements in the exact payment context. Customer/ephemeral-key credentials are returned only when this member owns the customer frozen by the first payment operation; admin-created or another accepted booker identity receives a safe generic sheet with null customer credentials. Idempotent (reuses the frozen PaymentIntent execution created at confirmation). `{ skipped: true }` when the event type’s payment_mode is `none`. Member-JWT; ownership by contact_email.
Member approves a quoted booking and gets Payment Sheet credentials
The member’s “Approve & pay” CTA: the booker confirms a quote the venue sent (status `quoted`) and receives the same frozen PaymentIntent, `merchant_country_code`, and `stripe_account_id` (`acct_*` only for direct Connect; otherwise null). Customer/ephemeral-key credentials are returned only to the user id that owns the frozen Stripe customer; another accepted booking identity receives a generic sheet with null customer credentials. Member-JWT; ownership by `booked_by` or `contact_email`. Idempotency-Key header REQUIRED — a retry re-enters the repairable confirmation pipeline and returns the same frozen execution (no duplicate PI, account drift, or regional drift). Honors the event type’s payment_mode via the shared helper; `{ skipped: true }` when payment_mode is `none` (invoice path).
PROMPT_11 — public catalog of a venue’s active, publicly-listed private-session types for the embeddable widget (/embed/private-sessions). Cross-origin access is governed by the platform dynamic CORS allowlist (venue custom domains). Cached, IP-throttled.
List products for the authenticated venue. Business-app JWTs require pos.access; API keys require read:products. Archived products are hidden unless include_archived=true.
Parameters, scopes and examples
Required scopes
read:products
Query parameters
include_archivedboolean
Include archived products. Defaults to false.Default: false
POST/api/v1/admin/productsAPI key
Create a venue product
Create through the canonical product mutation contract. Unknown/protected fields are rejected; initial stock creates one movement.
Parameters, scopes and examples
Required scopes
write:products
GET/api/v1/admin/products/{id}Bearer or API key
Get a venue product
Get one product only when it belongs to the authenticated venue. Business-app JWTs require pos.access; API keys require read:products.
Parameters, scopes and examples
Required scopes
read:products
Path parameters
idstring · required
Product UUID
PATCH/api/v1/admin/products/{id}Bearer or API key
Update a venue product
Update mutable catalog fields through the canonical product core. Business-app JWTs require products.manage; API keys require write:products. Products and its tier-gated Point of Sale dependency must be active. stock_quantity and protected fields are rejected.
Parameters, scopes and examples
Required scopes
write:products
Path parameters
idstring · required
Product UUID
DELETE/api/v1/admin/products/{id}API key
Archive a venue product
Archive through canonical catalog semantics (is_active=false plus archived_at). Permanent deletion is separate and guarded.
Parameters, scopes and examples
Required scopes
write:products
Path parameters
idstring · required
Product UUID
GET/api/v1/venues/{slug}/product-packagesPublic
List buyable clip cards
Public catalog of active product passes (clip cards) for a venue. Cached, IP-throttled.
Initiate a product-pass (clip card) purchase. A nonempty Idempotency-Key header is required and defines the durable operation. Returns Customer/ephemeral-key credentials in the same frozen Stripe account as the PaymentIntent, plus `merchant_country_code` and `stripe_account_id` (`acct_*` only for direct Connect; otherwise null). A service-only pre-provider claim binds tenant, catalog, customer, regional, routing, fee, amount, and currency; `product_passes` is granted atomically on `payment_intent.succeeded`. Gated on the `products` module + venue legal docs. Member-JWT.
Buy N paid tickets for a community event (`{id}` is the event booking id). Price = `member_price` + `guest_price` × (ticket_count − 1). Requires an Idempotency-Key header. Returns Customer/ephemeral-key credentials in the same frozen Stripe account as the PaymentIntent, plus `merchant_country_code` and `stripe_account_id` (`acct_*` only for direct Connect; otherwise null). On `payment_intent.succeeded` the ticket order flips to paid and a `going` RSVP is upserted with `guest_count = ticket_count − 1`. Gated on the `community_events` module. Member-JWT.
Inspect the contract. Build against generated truth.
This reference reads the same typed endpoint registry that generates Booking Bible’s OpenAPI 3.1 document. Start with a group, then open only the parameters and examples you need.
Route handlers are the complete deployed /api/v1 surface. Documented operations are the partner-facing contracts currently registered for OpenAPI.
Start with the contract
Authentication and versioning are explicit
Public discovery routes need no credentials. Protected routes accept a user bearer token, an organization-scoped API key, or the method documented for that operation.
Organization-scoped credentials
Create API keys under Admin → Settings → Developer. Each key is shown once, carries explicit scopes, and remains bound to its venue.
Version pinned by header
Send X-Api-Version to pin behavior. The current documented version is 2026-04-11.
Groups and operations below are generated from the application registry. Download the OpenAPI JSON for code generation or machine-readable inspection.
Discovery20 documented operations
GET/api/v1/discoveryPublic
Discover live venue inventory
Bounded, paginated Universe discovery for one canonical world and venue-local date. Returns capped live class or service/appointment summaries with explicit partial failures; member coordinates are not accepted.
Parameters, scopes and examples
Query parameters
worldstring · required
Required: classes, treatments, or salon
datestring · required
Required venue-local date (YYYY-MM-DD)
time_windowstring
any, morning, afternoon, or eveningDefault: any
searchstring
Venue, location, class, or service search
pageinteger
Page numberDefault: 1
limitinteger
Venue items per page (max 4)Default: 4
GET/api/v1/discovery/countsPublic
Live per-world "open today" venue counts
Lightweight counterpart to /api/v1/discovery for the Explore landing screen: how many venues actually have live same-day inventory in each world today, not how many venues merely support the world. Reuses the same same-day-activity signals as discovery ordering (classes: class_instances existence; treatments/salon: the union of provider_schedules rostering and real appointments existence — a same-day proxy, not exact slot availability).
Full venue profile including brands, locations with rooms, opening hours, amenities, and photos.
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/joinBearer token
Check venue join eligibility
Bearer-authenticated, read-only membership check for Consumer apps. Resolves the target from its slug or organization UUID and reports member, can_join, or an unavailable reason without changing account state.
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug or organization UUID
POST/api/v1/venues/{slug}/joinBearer token
Join a venue with explicit consent
Bearer-authenticated and Idempotency-Key protected. Requires {consent:true}; creates one active member relationship without changing an existing role, assigns the venue client ID, and emits the canonical audit, analytics, and member.created integration events.
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug or organization UUID
Explicit user consent to add this venue to their account.
Request body
{
"consent": true
}
GET/api/v1/venues/{slug}/schedulePublic
Get class schedule
Live class schedule with real-time availability. Filter by date range, location, brand, class type, instructor, or online-only. Each row includes the additive general-policy `requires_workshop_entry` flag and a nullable public `workshop_entry_target`; `is_bookable` retains its capacity/status/time meaning.
Bearer-authenticated exact class detail for Consumer push deep links. Requires X-Organization-ID for an active member relationship, retains public/member-entitled completed or cancelled classes, and never exposes an unlisted class. Includes the same additive general-policy `requires_workshop_entry` and nullable public `workshop_entry_target` fields as the venue schedule; `is_bookable` remains capacity/status/time-only.
All active pass types with pricing tiers, binding commitments, class restrictions, and location availability. Returns an `{ org, pass_types }` envelope (BB-R4): `org` carries `slug`, `name`, `currency`, `timezone`, and `vat_exempt_age_threshold` (for an under-/over-threshold pricing toggle); each `pass_types` entry includes its `slug` for `/buy/{slug}` deep-links. Configurable recurring entries also include `pricing_mode`, billing cadence, the immutable active pricing version, quantity range/step, volume tiers, unlimited option, and change-cycle policy. Optional `category`, `location_id`, `brand_id` filters apply to `pass_types`.
Class catalog with descriptions, difficulty levels, durations, and included services.
Parameters, scopes and examples
Required scopes
read:classes
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/instructorsPublic
Get instructors
Instructor profiles with bios, photos, and specialties.
Parameters, scopes and examples
Required scopes
read:instructors
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/locationsPublic
Get locations
Physical locations with rooms, capacity, opening hours, amenities, and Google Maps integration.
Parameters, scopes and examples
Required scopes
read:locations
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/brandsPublic
List brands
Active brands at this venue. Each entry includes identity (name, slug, description), theming (colors, logo, hero), social links, and a class_types_count for quick summary rendering.
Parameters, scopes and examples
Required scopes
read:brands
Path parameters
slugstring · required
Venue URL slug
GET/api/v1/venues/{slug}/brands/{brandSlug}Public
Get brand detail
Full brand record plus class_types tagged to this brand and the pass_types available for it (respecting pass_type_brands restrictions — passes with no brand-junction rows are venue-wide and are included).
Parameters, scopes and examples
Required scopes
read:brands
Path parameters
slugstring · required
Venue URL slug
brandSlugstring · required
Brand slug within the venue
GET/api/v1/geoPublic
Geo prefill for the signup form
Anon utility that reads Vercel's request-geo headers (`x-vercel-ip-country`/`x-vercel-ip-city`) so a client can prefill signup's optional `country`/`city` fields from the caller's own IP before submitting POST /api/v1/auth/signup. `country` is an ISO 3166-1 alpha-2 code; `city` is URI-decoded free text. Either is `null` when the header is absent (e.g. local dev). No DB touch; never cached (per-caller response).
PUBLIC (no auth) balance-by-code lookup for a venue gift card, for a storefront "check your balance" widget. Org resolved from {slug}; lookup scoped to that org's cards by the FULL code. Returns the minimal `{ code, remaining_amount, currency, status, expires_at }` — never purchaser/recipient PII. Enumeration-hardened: an unknown code, a cross-org code under the wrong slug, and a cancelled card all return the SAME generic 404. IP rate-limited (20/min).
PUBLIC (no auth) gift-card preview so a BRANDED storefront can show a recipient what they were gifted ("Alex sent you a 3-month membership") before prompting signup/redeem — instead of bouncing them to BB's /gift/redeem/[code] venue portal. Returns `{ code, gift_type, sender_name, gift_description, amount, currency, status, expires_at }` — the sender's display name + a human gift description only, NEVER recipient/purchaser contact info, the personal message, or the redeemer. Enumeration-hardened: unknown code, wrong slug, and a cancelled card all return the SAME generic 404. IP rate-limited (20/min). Redeem itself is member-authenticated (POST /api/v1/gift-cards/redeem).
Member-authenticated request-a-booking for a service that accepts inquiries (`accepts_inquiries: true` on the public services list). Free-text preferred time, not a real slot — the venue converts it to a real appointment once a time is agreed. `Idempotency-Key` is optional but MUST be a UUID when sent (400 `INVALID_IDEMPOTENCY_KEY` otherwise); it is the database ingest request id. Every 201 and every 503 `INQUIRY_RECONCILE_FAILED` returns an `Idempotency-Key` RESPONSE header (mirrored as `error.details.request_id` on the 503) carrying the identity the inquiry was accepted under — your key when you sent one, the server-generated UUID when you did not. Retry a 503 with that exact value as `Idempotency-Key`: it replays the accepted inquiry (no second row) and re-drives only what is still missing. Retrying without it mints a new identity and files a duplicate inquiry. Rate-limited 10/min. Errors: 503 INQUIRIES_DISABLED (kill switch off), 404 NOT_FOUND (venue), 422 SERVICE_NOT_ACCEPTING_INQUIRIES, 422 VALIDATION_FAILED, 409 IDEMPOTENCY_KEY_REUSE_MISMATCH (same key, different answers — nothing written), 500 SUBMIT_FAILED (`details.reason` passthrough).
Parameters, scopes and examples
Path parameters
slugstring · required
Venue URL slug
Inquiry details
Request body
{
"service_id": "uuid",
"preferred_time": "Tuesdays or Thursdays after 17:00",
"message": "Looking for a 90-minute deep tissue session.",
"contact_name": "Jane Doe",
"contact_email": "jane@example.com",
"contact_phone": "+4520123456"
}
Response example
{
"data": {
"id": "uuid"
},
"error": null
}
GET/api/v1/me/inquiriesBearer token
My booking inquiries
The caller's own booking inquiries across every venue, newest first. Status is mapped to plain language (never the raw form_submissions enum): 'Sent — waiting for the venue', 'The venue replied', or 'Closed'; archived/spam/deleted rows are never returned.
Exchange a device-bound mobile token_hash or a 6-digit email OTP for a session. Mobile token hashes require the callback request_id and device-held code_verifier. Rate-limited 5/10 min per IP.
Check whether an email already has an account before signup. Returns a state hint (absent | active | password_never_used | imported_unclaimed | unknown). Rate-limited 20/min per IP. Constant-time floor of 250ms to prevent enumeration.
Create a TOTP challenge for one of the caller's factors. Returns {id, expires_at}; pass the id as challenge_id to /auth/mfa/verify. Repeating mints a fresh challenge (intended resend). Rate-limited 5/min per user.
Verify a 6-digit TOTP code (enrollment confirmation or login challenge). Accepts {type: totp, factor_id, code}, {type: backup_code, code}, or the challenge-bound {challenge_id, code} (factor resolved from the preceding /mfa/challenge). Rate-limited 5/5 min per user.
Generate 10 single-use backup codes for MFA recovery. Previous unused codes are invalidated. Codes are shown once in plaintext — only hashes are stored.
Parameters, scopes and examples
Response example
{
"data": {
"backup_codes": [
"ABCD1234EF",
"..."
],
"warning": "Save these codes securely. They will not be shown again.",
"count": 10
}
}
POST/api/v1/auth/mfa/resetBearer or API key
Admin MFA reset
Admin-initiated MFA reset for a user. Unenrolls all factors and invalidates backup codes. Permission: admin.users.manage.
Exchange refresh token for new access and refresh tokens.
Parameters, scopes and examples
Refresh token
Request body
{
"refresh_token": "xxx"
}
POST/api/v1/auth/logoutBearer token
Log out current session
Revoke the refreshable Supabase session represented by the caller JWT. The access JWT remains valid until its encoded expiry.
Parameters, scopes and examples
Response example
{
"data": {
"ok": true
}
}
POST/api/v1/auth/password/forgotPublic
Forgot password
Send a single-use 6-digit password verification code. Honours venue branding when an org is identified and never reveals whether the email exists. No reset link is generated.
Authenticated password change that still requires a fresh single-use numeric code. Submit the code and new password together; current-password-only and session-only changes are rejected.
NAMASTE-GATES-01 — mint a one-time SSO handoff code (60s TTL, single-use, SHA-256 hashed at rest) bound to an allowlisted destination domain. The destination site exchanges it at /auth/handoff-exchange for a fresh session.
NAMASTE-GATES-01 — consume a one-time handoff code (atomic single-use) and receive a fresh Supabase session for the bound user. Same session shape as /auth/login.
TV-DEVICE-AUTH-01 — RFC 8628-style device authorization (mint side). An input-constrained device (TV) receives a 256-bit device_code (its poll credential) plus a short user_code (shown as XXXX-XXXX + QR). Both are SHA-256 hashed at rest, bound to one 10-minute expiry, single-use.
TV-DEVICE-AUTH-01 — a SIGNED-IN member submits the user_code shown on the TV (normalized: uppercase, dashes/spaces stripped). Binds the pending device code to the caller so the TV poll returns a session. Every failure (unknown / expired / attempts-capped) is the same generic 400 INVALID_CODE; per-code attempts<5 cap.
Parameters, scopes and examples
The short code shown on the TV
Request body
{
"user_code": "ABCD-EFGH"
}
Response example
{
"data": {
"approved": true
}
}
POST/api/v1/auth/device/tokenPublic
Poll TV device code for session
TV-DEVICE-AUTH-01 — the TV polls with its device_code (every `interval` seconds). 400 AUTHORIZATION_PENDING until approved; 400 EXPIRED_TOKEN / 403 ACCESS_DENIED / 400 INVALID_CODE are terminal. On approval the code is consumed atomically (single-use) and a fresh Supabase session is returned — same shape as /auth/login.
Venue-local YYYY-MM-DD start of a pass usage cycle (inclusive). Requires organization_id.
cycle_endstring
Venue-local YYYY-MM-DD end of a pass usage cycle (exclusive). Requires organization_id.
afterstring
Cursor for pagination
limitinteger
Items per pageDefault: 20
POST/api/v1/bookingsBearer or API key
Book a class
Create a booking. Validates pass eligibility, capacity, booking window, daily limits, and class restrictions. Supports idempotency via Idempotency-Key header.
Retrieve a single booking with class details, pass info, and check-in status.
Parameters, scopes and examples
Required scopes
read:bookings
Path parameters
idstring · required
Booking ID
POST/api/v1/bookings/buddyBearer token
Invite a client to the same class
Creates and emails a venue-branded invitation to an existing active client at the same venue. The inviter must already have a confirmed booking. The recipient books with their own pass or payment; no guest funding or inviter entitlement is used. Idempotency-Key supported.
Accepts a buddy invitation for the authenticated recipient and books the same class with that recipient’s own eligible pass or normal venue booking rules. The invited email/account and active venue membership must match. Idempotency-Key supported.
NAMASTE-GATES-01 / LIVE-PARTICIPATION-01 — entitlement-based live-watch path. Requires an active pass whose type grants online class access and covers the class type; finds or creates the caller’s attendance_type=online booking (idempotent, respects online_capacity, consumes a clip only for clip-based passes) and returns a signed Mux playback URL plus viewer-session telemetry token. First admission opens 10 minutes before start and closes exactly at start; an admitted viewer may recover through end + 5 minutes unless they explicitly leave after start.
Client-facing: exchange a valid QR token for a check-in on the caller's booking. Token must be active and not expired. Anti-replay: a booking can only transition to checked_in once. Every scan writes an audit_log entry regardless of outcome.
Pass-type catalog detail used by checkout — price, duration, benefits, binding tiers, eligible class types, and the published flexible recurring configuration when enabled. Active public items need no authentication; a hidden exhausted-credit target requires member JWT authentication plus its clips_empty_offer_id capability.
Parameters, scopes and examples
Path parameters
idstring · required
Pass-type id
Query parameters
clips_empty_offer_idstring
Opaque clips-empty path UUID. Revalidated against the authenticated member’s exhausted, still-valid source pass before a hidden target is returned.
Initiate pass purchase. Returns a PaymentIntent or SetupIntent client_secret (`client_secret_type` identifies which) with the provider-frozen customer, ephemeral key, Connect account, merchant country, and regional revision. Customer credentials are paired and may both be null only for a supported generic-sheet/no-customer result. Optional binding_months must identify a current server-side tier and is priced by the same canonical resolver as checkout preview; unavailable tiers return 422 rather than falling back. Configurable recurring passes require selection_kind=quantity with quantity, or selection_kind=unlimited. Fixed passes support promo codes, gift cards, and account credits.
MEMBER (JWT) redeem endpoint so a branded storefront can host the whole redeem flow on its own domain. Applies the gift `{ code }` to the caller's account: a custom-amount gift credits the balance (`{ type:"credit", amount, newBalance }`); a pass gift creates + activates a pass (`{ type:"pass", passId }`). Atomic SELECT FOR UPDATE claim — two concurrent calls can never both redeem. A logged-out recipient must sign up / log in first (that creates/links the BB member); this endpoint is member-only by design. Org from the caller's active membership (X-Organization-ID header or single membership). Errors: 401 UNAUTHORIZED, 403 NO_ORG / MODULE_DISABLED, 400 VALIDATION_ERROR, 404 INVALID_CODE, 409 ALREADY_REDEEMED / EXPIRED / NOT_AVAILABLE, 500 REDEEM_FAILED.
Parameters, scopes and examples
Gift card code to redeem onto the caller's account
Gift cards the caller purchased or received (buyer, redeemer, or addressed recipient email), scoped to the active org. Returns `{id, code, initial_amount, balance, currency, status, recipient_email, recipient_name, message, expires_at, created_at}` with status `active|redeemed|expired|void`. Degrades to an empty list when the gift_cards module is off or no org context resolves.
POST/api/v1/gift-cards/purchaseBearer token
Purchase gift card
Buy a gift card (custom amount or a gifted pass) for a recipient. Creates a Stripe one-time PaymentIntent and returns client_secret plus customer_id + ephemeral_key for the Stripe Payment Sheet. Gated on the gift_cards module. Idempotency-Key supported.
Parameters, scopes and examples
Gift card purchase
Request body
{
"gift_type": "custom_amount",
"organization_id": "uuid",
"amount": 500,
"sender_name": "Alex",
"recipient_name": "Jordan",
"recipient_email": "jordan@example.com",
"delivery_method": "email",
"personal_message": "Enjoy a class on me!"
}
Anonymous (or logged-in) native gift-card checkout — phase 1. Mints a Stripe PaymentIntent for a gift card and returns client_secret so the buyer can mount Stripe Elements in a modal. Two gift kinds (exactly one of the two fields): a CUSTOM-AMOUNT gift via `amount` (smallest currency unit, min 5000, max 5000000), or a PASS-BASED gift via `pass_type_id` (GIFT-PASS-API-01 — must be an active, giftable, non-intro pass type of this org; price is server-resolved via calculateGiftPrice, optional `duration_months` 1–120 prepays a recurring membership). The gift_cards row is created only on confirm, so an abandoned payment leaves no orphan. Anonymous callers must pass a Turnstile token. VAT is accounted at redemption (multi-purpose voucher) so vat_amount is 0. Gated on the gift_cards module. Rate-limited 10/min.
Parameters, scopes and examples
Gift card checkout — custom-amount example; for a pass gift replace `amount` with `pass_type_id` (+ optional `duration_months`)
Request body
{
"organization_slug": "hot-yoga-cph",
"amount": 50000,
"recipient_email": "jordan@example.com",
"recipient_name": "Jordan",
"sender_name": "Alex",
"message": "Enjoy a class on me!",
"giver_email": "alex@example.com"
}
Native gift-card checkout — phase 2. After the buyer confirms the PaymentIntent client-side, this creates the gift_cards row (custom-amount OR pass-based — the pass identity rides in PI metadata), delivers it to the recipient, and emails the giver a receipt. Idempotent on the PaymentIntent — a retry or the webhook backstop never double-creates a card. Returns the last 4 of the code, a masked recipient email, and gift_type. organization_slug is optional but recommended for direct-charge venues.
Pause (freeze) a pass for a date range. Owner-scoped. Enforces the pass-type pause rules (allow_pause, min/max duration, annual freeze budget) + binding gate, pauses Stripe billing, and bills any pause fee. Idempotency-Key supported.
Move a deferred (pending_activation) membership start to today or an earlier future date: re-anchors Stripe billing, charges the first membership payment, and activates the pass. Owner-scoped. Idempotency-Key supported; rate-limited 5/min. Returns payment_status succeeded | requires_action (confirm with client_secret; the invoice.paid path then activates) | pending. Errors: PASS_NOT_FOUND, FORBIDDEN, ALREADY_STARTED, IN_PROGRESS, INVALID_START_DATE, PAYMENT_FAILED, STRIPE_UNAVAILABLE.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
New start date (must be earlier than the current start)
Owner-scoped, read-only termination summary resolved from the venue self-cancel gate, binding period, termination policy, Stripe billing boundary and remaining class balance. Returns can_confirm=false with the blocking reason while a binding period is active.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
POST/api/v1/me/passes/{id}/terminateBearer token
Terminate a recurring membership
Confirmed owner-scoped membership termination. Enforces venue allow_member_cancel, minimum membership age, binding period, required reason and the configured termination boundary. Stripe synchronization is fail-closed and Idempotency-Key is supported.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
Explicit acknowledgement and optional/venue-required reason
Request body
{
"acknowledged": true,
"reason": "Moving away"
}
GET/api/v1/me/passes/{id}/extensionBearer token
Get pass extension quote
Return the authenticated member’s venue-scoped self-extension policy and live quote: proposed expiry, price/currency, configured duration, remaining extension allowance, clips, and a machine-readable unavailable_reason. Requires X-Organization-ID and fails closed on invalid venue configuration.
Revalidates the venue’s live self-extension policy and creates a durable operation before any processor call. Paid responses include PaymentSheet customer/ephemeral-key credentials in the exact frozen Stripe namespace; direct mode returns stripe_account_id. Free responses still return operation_id but do not mutate the pass. Requires X-Organization-ID and Idempotency-Key.
Authoritatively rechecks owner, tenant, venue policy, maximum count, hard end, frozen Stripe provenance and payment status under database locks. Paid success atomically records payment, fee, audit, pass, and operation; explicit post-charge conflicts are idempotently refunded. Nonterminal 202 statuses are finalizing or refund_pending and are safe to retry. The Stripe webhook shares this reconciler. Idempotency-Key is required.
Parameters, scopes and examples
Path parameters
idstring · required
Pass id
Durable operation reference plus PI reference for paid extensions
Request body
{
"operation_id": "uuid",
"payment_intent_id": "pi_xxx (omit when free)"
}
Accept a pending pass-share invitation by token. Verifies the caller’s email matches the invite recipient, then grants booking access by appending the caller to `passes.shared_with` (respecting `pass_types.max_sharers`) and converges the share into the `pass_shares` table. Emits `pass.share_accepted`. Member-JWT. Idempotency-Key supported.
Published VODs and class replays for the caller's venue. Visibility public + members only; pass_restricted items are accessible via /video-catalog/:id once the pass check passes. Signed Mux playback URLs valid for 2 hours.
Parameters, scopes and examples
Query parameters
pageinteger
Page numberDefault: 1
limitinteger
Items per page (max 50)Default: 20
categorystring
Filter by category (class_recording | tutorial | workshop)
The caller's required/pending intake forms for their active org. Each entry is annotated with whether the member already submitted (the pre-booking form gate's source of truth). Returns [] when the `forms` module is disabled.
Parameters, scopes and examples
Response example
{
"data": [
{
"id": "uuid",
"slug": "new-client-intake",
"name": "New Client Intake",
"description": "Tell us about your practice and any injuries.",
"required": true,
"submitted": false,
"submission_id": null,
"submitted_at": null
}
]
}
GET/api/v1/forms/{id}Bearer token
Get form schema
Render schema (fields, steps, submit label) plus the venue's configured `legal_basis` (`consent` | `contract` | `legitimate_interest` | `legal_obligation`) for a single published form. Use `legal_basis` to render the matching privacy notice and, for a `consent` form, to present its required consent checkbox as the gate it is — a consent-basis submission is refused unless that box was ticked. Scoped to the active org — forms in other orgs return 404.
Parameters, scopes and examples
Path parameters
idstring · required
Form UUID
Response example
{
"data": {
"id": "uuid",
"slug": "new-client-intake",
"name": "New Client Intake",
"description": "Tell us about your practice and any injuries.",
"required": true,
"legal_basis": "consent",
"schema": {
"version": 1,
"fields": [],
"steps": null,
"submit_label": "Submit"
},
"thank_you": {}
}
}
POST/api/v1/forms/{id}/submitBearer token
Submit a form
Submit `{ answers }` for a published form. Validates required fields + types, persists a submission stamped with the caller, and routes it into the unified inbox. `Idempotency-Key` is optional but MUST be a UUID when sent (400 `INVALID_IDEMPOTENCY_KEY` otherwise) — it is both the HTTP replay token and the database ingest request id. The same key with the same answers replays the original response; the same key with different answers writes nothing and returns 409 `IDEMPOTENCY_KEY_REUSE_MISMATCH`, so mint a new key whenever the answers change. Every 201 and every 503 `SUBMIT_RECONCILE_FAILED` returns an `Idempotency-Key` RESPONSE header (mirrored as `error.details.request_id` on the 503) carrying the identity the submission was accepted under — your key when you sent one, the server-generated UUID when you did not. Retry a 503 with that exact value as `Idempotency-Key`: it replays the accepted submission and re-drives only the missing delivery. Retrying without it mints a new identity and files a duplicate. 422 with `details.missing[]` on required-field failures; 422 `CONSENT_REQUIRED` when a consent-basis form was sent without its consent box ticked; 409 `FORM_CONSENT_MISCONFIGURED` when the form itself cannot lawfully collect.
The caller's referral status for their active org: code, referred-friend count, conversions, rewards earned, and an anonymized (first-name + last-initial) per-referral list. Returns an empty summary when the `referrals` module is disabled.
Active public venues ranked by explicit favourite, then canonical pass, class-booking, and appointment signals. Returns counts and last activity; caller identity is server-bound.
Idempotently removes only the authenticated member and requested venue pair.
Parameters, scopes and examples
Path parameters
organizationIdstring · required
Venue organization UUID
GET/api/v1/me/credits/balancesBearer token
My venue credit balances
Complete ledger-derived balances grouped by venue and currency. Each row carries `balance` (the venue ledger total), `available` (that total minus credit held by open checkout reservations, which is what checkout will actually spend) and `reserved`. Amounts are in major units. Consumer is account-wide; branded requests are fail-closed to x-organization-slug.
POST/api/v1/me/avatar/upload-urlBearer token
Create avatar upload ticket
Returns a caller-owned, MIME-bound storage path and two-hour signed upload URL for PNG, JPEG, or WebP up to 5 MB.
PATCH/api/v1/me/avatarBearer token
Finalize my avatar
Validates caller path ownership, metadata, size, and image magic bytes before deriving and saving the public URL.
DELETE/api/v1/me/avatarBearer token
Remove my avatar
Idempotently clears the profile reference and removes only the caller-owned canonical avatar object.
GET/api/v1/me/workspace-profileBearer token
My active venue operating profile
Server-authoritative Business-app profile for the active venue selected by X-Organization-ID. Returns booking_mode (classes, appointments, or both), business_type, resolved class/appointment operation gates, venue surface applicability, appointment access/counts, active_modules, and the resolved vertical_modules visibility map. business_type is informational and never used to infer booking_mode. Surface values are venue-level applicability; clients must still intersect them with the caller's effective permissions from GET /api/v1/me.
Current user profile with all active venue memberships and roles. Each membership carries `permissions: string[]` (the caller's OWN effective permission keys for that org — per-user overrides applied over role/capability defaults, resolved identically to requireApiPermissionWithDefaults) and `capabilities: string[]` (the membership capability set, surfaced for every membership). To bound per-request cost in this multi-tenant app, `permissions` is resolved for the ACTIVE org only (top-level `permissions_scope: "active_org"`; non-active memberships carry `[]`) — mobile refetches /me on org switch. Workspace ownership is server-projected as `is_individual`, `is_owned`, `is_workplace`, `is_relationship`, `is_selectable`, and an explicit `workspace_group` (`owned`, `works_at`, `member_venues`, or `relationships`). Accepted role-bearing employer memberships remain selectable in Business under “Works at”; member-only Network relationships do not. Business clients must only put selectable rows in their workspace picker. Gates UI on these instead of discovering denials via 403s. A PATCH /admin/permissions/user/{userId} is reflected within ≤60s (permission-cache TTL). Caller's own permissions only. See docs/api/ME_PERMISSIONS_CONTRACT.md.
POST/api/v1/me/active-organizationBearer token
Switch my active workspace
Authoritatively switches the caller to an active, selectable workspace. When the caller owns an individual professional venue, accepted role-bearing employer memberships remain selectable; only non-operational/member-only relationships return WORKSPACE_NOT_SELECTABLE. The response includes effective permissions for the selected workspace so native role gating is safe immediately.
Resolved feature-module map for the caller's active org (C07): `{ <module_key>: { enabled, source, tier?, settings? } }` — the same four-tier resolution (plan → group → venue → tenant) the admin sees at /admin/features. Also includes `professional_collaborations`, which reflects the platform-wide teacher-settlements rollout independently of the venue-to-venue `network` plan gate. Drives every <FeatureGate> in the branded mobile app. Multi-membership callers must send X-Organization-ID; without it the map resolves empty (all off).
GET/api/v1/me/minimalPublic
Minimal auth check
Cross-origin auth check for venue marketing sites. Returns { logged_in, first_name, venue_id, preferred_brand_id } — or logged_in=false when no session. CORS is gated by the venue/brand embed_allowed_origins allowlist; unknown origins get no CORS headers (treated as "not logged in" by the caller).
GET/api/v1/me/entitlementsBearer token
My entitlements
NAMASTE-GATES-01 — the caller's entitlement matrix for one venue: can_book_physical (any active pass with grants_in_person), can_watch_online (grants_online_class_access), online_only, bookable_class_type_ids ("all" when any usable pass is unrestricted), and an active_passes[] summary (slug, category, grants, validity, clips). The create_booking RPC enforces the same matrix atomically.
Create an account-local Stripe SetupIntent plus matching Customer/ephemeral-key credentials. Requires an Idempotency-Key header. The response freezes the server-owned venue country and exact Connect account for native Payment Sheet initialization.
Promote a saved card to the Stripe customer default (invoice_settings.default_payment_method). Empty body, idempotent via Idempotency-Key. GET /me/payment-methods then returns is_default:true on the matching row (PAY-P3.1).
Parameters, scopes and examples
Path parameters
idstring · required
Stripe payment method ID
POST/api/v1/me/payment-sheet-initBearer token
Initialise Payment Sheet
Setup-only flow for Stripe Payment Sheet (PAY-P1.1). Requires an Idempotency-Key header. Returns customer_id, ephemeral_key, setup_intent_client_secret, and apple_merchant_id in the exact SetupIntent home account: connected only in direct mode, otherwise platform. Use when collecting a saved card before any purchase.
Register an Expo push notification token for iOS/Android/web. app_variant is required so member, branded-venue, and staff deliveries cannot cross application boundaries. Branded and business tokens also require a validated organization context.
Deactivate the authenticated user's token or device before logout. The token/device selector is sent in the JSON body.
Parameters, scopes and examples
At least one token or device_id is required
Request body
{
"device_id": "installation-uuid"
}
GET/api/v1/me/notificationsBearer token
Notification history
Cursor/page-paginated email, SMS, push, and in-app history. Rows include source-aware `data`, `read_at`, and `app_variant`; X-App-Variant filters app-specific inbox events, while X-Organization-Slug narrows branded clients to their venue.
Self-scoped read marker. Idempotency-Key is required; another user’s row returns 404.
Parameters, scopes and examples
Path parameters
idstring · required
Notification id
POST/api/v1/me/notifications/read-allBearer token
Mark notifications read
Marks all of the caller’s unread rows read. X-Organization-Slug narrows a branded client to its exact venue; otherwise Consumer marks its cross-venue inbox. Idempotency-Key is required.
Returns the canonical ten-category catalog with effective email/SMS/push defaults, frequency caps, and per-member quiet hours for the active/requested organization.
Upserts canonical category toggles/frequency caps and quiet hours. Unknown categories are rejected and every database failure is returned; Idempotency-Key is required.
GET/api/v1/me/paymentsBearer token
List my payments
Cursor-paginated receipt-bearing payment ledger for the caller. Pending and failed attempts are excluded; successful, refunded, partially-refunded and disputed originals remain available with their payment receipt.
Parameters, scopes and examples
Query parameters
limitnumber
Page size (default 20, max 100)
afterstring
Opaque cursor from a previous page
GET/api/v1/me/invoicesBearer token
List my invoices
Cursor-paginated list of the caller's member-visible client invoices. Drafts are excluded and every row includes an authenticated document_path for the print-ready HTML invoice.
Parameters, scopes and examples
Query parameters
limitnumber
Page size (default 20, max 100)
afterstring
Opaque cursor from a previous page
GET/api/v1/me/invoices/{id}Bearer token
Invoice detail
Owner-scoped detail for one issued client invoice, including line items and the totals breakdown (subtotal, discount, VAT, total, amount_paid).
Streams the receipt PDF (application/pdf) for one of the caller's payments — branded merchant header, line items, VAT breakdown, totals. Cached in storage after first render.
Emails the venue-branded receipt PDF for one of the caller's own payments to the address already on file for their account — the same document served by the PDF download. No recipient field exists; any caller-supplied recipient is ignored. Idempotency-Key is required; a retried key replays the cached result instead of re-sending.
Parameters, scopes and examples
Path parameters
paymentIdstring · required
Payment id
Empty body — the request is never read.
Request body
{}
GET/api/v1/me/invoices/{id}/documentBearer token
Invoice print document
Authenticated owner- and venue-scoped print-ready HTML for one member-visible invoice.
Parameters, scopes and examples
Path parameters
idstring · required
Invoice id
GET/api/v1/me/refundsBearer token
List member refund receipts
Owner-scoped successful refund operations, cursor-paginated and optionally restricted by the branded organization slug. Split-tender operations are returned once with a signed negative amount.
Parameters, scopes and examples
Query parameters
limitnumber
Page size (default 20, max 100)
afterstring
Opaque cursor from a previous page
GET/api/v1/me/refunds/{refundId}/pdfBearer token
Refund receipt PDF
Owner- and venue-scoped canonical refund receipt PDF. Non-final, sibling, cross-member and cross-venue refund ids return a uniform not-found response.
Parameters, scopes and examples
Path parameters
refundIdstring · required
Refund id
GET/api/v1/me/loyaltyBearer token
Loyalty balance + history
The caller's org-scoped loyalty point balance plus a recent per-event history slice. Full paginated history is on /api/v1/me/loyalty/points.
GET/api/v1/me/loyalty/pointsBearer token
Loyalty points history
Cursor-paginated per-event loyalty point ledger for the caller.
GET/api/v1/me/streakBearer token
Attendance streak
Current + longest attendance streak, freezes remaining, and at-risk flag.
GET/api/v1/me/rewardsBearer token
Redeemable rewards catalog
Active loyalty rewards for the caller's org with affordability (is_locked) computed against the caller's balance.
POST/api/v1/me/rewards/redeemBearer token
Redeem a reward
Redeem a loyalty reward. Idempotency-Key supported; audited.
Parameters, scopes and examples
Redemption
Request body
{
"reward_id": "uuid"
}
POST/api/v1/feedbackBearer token
Submit feedback & tip
Rate a class (1-5 stars), leave a comment (optionally `anonymous`), and optionally tip the instructor via Stripe. The tip carries its own `anonymous` flag. The tip block of the response returns `client_secret`, `customer_id`, `ephemeral_key`, and `stripe_account_id` (non-null only in DIRECT charge mode).
Self-scoped class/appointment review and tip eligibility. Organization, target, settings, MobilePay capability, and prompt decision are server-derived from the owned source. Reads are side-effect-free unless `claim_prompt=true` is explicitly supplied by a prompt-mode entry check.
Parameters, scopes and examples
Query parameters
source_typestring · required
class or appointment
source_idstring · required
Owned booking id (class) or appointment id
claim_promptboolean
Reserve an in-app prompt only when true
POST/api/v1/post-attendance/reviewsBearer token
Submit class or appointment review
Creates one source-aware review after server-authoritative attendance/settings checks. Idempotency-Key required. `professional_rating`, tags, recommendation, anonymity, moderation, recipient notification, analytics, and webhooks are venue-controlled.
POST/api/v1/tipsBearer token
Tip a professional (no review)
Create a class or appointment tip in major currency units (`amount: 20` means DKK 20). Organization, professional, currency, Stripe account, and available methods are server-derived. Customer + ephemeral key are optional: customerless PaymentSheet still supports adding a card. MobilePay is returned only for verified Danish/DKK/venue-capable configurations. Idempotency-Key required.
Authenticated tipper-only reconciliation after PaymentSheet/MobilePay/3DS returns. Retrieves the server-owned PaymentIntent in its frozen Stripe account namespace, validates amount/currency/metadata, and emits receipts only after Stripe reports succeeded. Idempotency-Key required.
Parameters, scopes and examples
Path parameters
idstring · required
Tip id
GET/api/v1/tips/{id}Bearer or API key
Tip status
Poll a tip's status after confirming its PaymentIntent (incl. MobilePay / 3DS redirect returns). Access: the tipper (JWT), an org admin/manager (JWT), or an org-scoped API key. Cross-user / cross-tenant reads return 404.
Submit an Art. 15/16/17/20/21/22 request (access, erasure, portability, rectification, objection, art22 review). 30-day SLA. For erasure, account access is disabled immediately and the response reports erasure_status=pending_fulfillment; a super-admin performs the guarded erasure cascade within the SLA, while the SLA cron only alerts. Statutory records may be anonymised and retained for their legal period. Idempotency-Key required.
Parameters, scopes and examples
DSR request
Request body
{
"kind": "access",
"details": "Please send all data you have on me."
}
Re-trigger the guardian verification email for the caller's outstanding parental-consent request (C06). Matched by the authenticated email — no enumeration. Rotates the token and refreshes the 7-day expiry on the existing pending row (never a duplicate request). Empty body; Idempotency-Key supported; throttled 3/min per IP + 5/hr per user.
GET/api/v1/me/consent-statusBearer token
Active consents
Latest consent record per consent_type for the authenticated user (TOS, marketing, cookies, AI, etc). is_active is fail-closed and true only when the grant is unwithdrawn and policy_version matches the server-canonical current_policy_version; stale grants return requires_reacceptance=true.
GET/api/v1/me/consentBearer token
Current native consent state + venue requirement
The venue's photo/video consent requirement (when organization_id is given) plus the caller's version-aware state for legal, marketing, analytics, and photo/community consent types. A stale policy version is inactive and requires reacceptance.
Parameters, scopes and examples
Query parameters
organization_idstring
Resolve the venue photo-consent requirement
POST/api/v1/me/consentBearer token
Capture native consent
Grant or withdraw one supported legal, marketing, analytics, or photo/community consent for the caller. Grant versions are resolved exclusively from the server-canonical active policy; legacy client policy_version values are accepted but ignored, and an unavailable policy returns 503 without writing. Delegates to the canonical consent record/withdraw pipeline (audit + webhook).
The caller's health-questionnaire completion timestamp (completed_at, null when never submitted). Pre-check for the mobile hot-yoga booking gate.
POST/api/v1/me/health-questionnaireBearer token
Submit health questionnaire (Art. 9)
Submit the spa/hot-yoga health questionnaire for the caller's active org. Runs the Art. 9 contraindication consent gate, inserts a health_questionnaires row (plaintext responses; encrypted at rest by cron), stamps profiles.health_questionnaire_completed_at so the booking gate clears, and writes audit_log/user_events. Requires an Idempotency-Key (a double submit replays). Org resolved via X-Organization-ID / active membership.
Read the caller's external calendar-feed state: { token, enabled, generatedAt }. token is the opaque secret embedded in the public .ics feed URL (null when no feed is provisioned).
Enable the caller's external calendar feed and return the token. Idempotent — an existing token is returned unchanged (never rotated); a new one is minted (256-bit, base64url) only when absent. Empty body. Audited (calendar_feed_token_generated).
Revoke the caller's calendar feed: clears the token and disables the feed (the public feed then 404s). Empty body. Audited (calendar_feed_token_revoked).
Parameters, scopes and examples
Response example
{
"data": {
"enabled": false
},
"error": null
}
GET/api/public/calendar-feed/{token}Public
Public calendar feed
UNAUTHENTICATED — the opaque token in the path IS the credential. Returns one user's bookings as JSON for an external calendar subscription: { bookings, cancellations, userId, generatedAt }. bookings are upcoming events for the next 90 days; cancellations are bookings cancelled in the last 7 days (so calendar apps emit STATUS:CANCELLED). 404s on an unknown or disabled token (indistinguishable). Scoped strictly to the token's single user — no other user's data. 60 req/min per token.
Buyer-facing canonical PricingBreakdown for a pass type — net/VAT split, registration fee, total today + recurring, localized policy terms, the start-date window, the required legal artifacts (with already_signed), and the buyer's saved signatures. NO charge. Member-JWT + stable x-organization-id (preferred) or legacy x-organization-slug, both membership-scoped. Query: pass_type_slug (required), start_date, binding_months, locale (en|da). A selected binding tier is validated and priced server-side; unavailable tiers return 422.
POST/api/v1/me/checkout/sign-artifactBearer token
Sign a purchase-time legal artifact
Records a waiver / ToS / privacy / contract acceptance with IP + user-agent + version + signature. Idempotent on (user, document, version); a stale version → 409 force-refetch; a minor (DOB < 18) → 409 + parental consent. Supports saved-signature reuse (saved_signature_id) honouring signature_kind. Linked contracts require pass_type_slug and may include start_date; the endpoint idempotently creates/adopts the exact current-version pre-purchase contract before signing.
GUEST-INVITE-01 — whether the caller's passes qualify them to host a guest at this class, the venue guest price, the standard single-class price to strike through (compare_at_price, display only), and any invitations they already have open for it. `reason` is plain-language copy safe to render verbatim when `eligible` is false.
Creates the invitation plus its pending guest seat (a GUEST-PAY-01 `pending_payment` booking that holds NO capacity until paid). `payer:'guest'` returns the link to share; `payer:'host'` additionally returns a Stripe Checkout URL (saved card, new card, or MobilePay). `return_base_url` must be an allowlisted host or it is ignored.
Withdraws an UNPAID invitation and releases its pending seat. A paid guest spot is a real booking — cancel it through the normal booking cancellation path so the venue's refund and fee rules apply (409 `ALREADY_PAID`).
GET/api/v1/guest-invites/{token}Public
Resolve a guest invitation (public)
GUEST-INVITE-01 — the invitation landing page a friend opens. Anonymous-allowed by design (the token is the capability); returns who invited them, the class, the price and the struck-through standard price, and nothing else about the host's account. `state` is `needs_account` for a signed-out visitor, `payable` once signed in, plus `already_paid` / `cancelled` / `expired` / `class_started` / `class_full`.
POST/api/v1/guest-invites/{token}/checkoutPublic
Pay a guest invitation without an account
GUEST-INVITE-01 — the Guest Visitor branch. ANONYMOUS-ALLOWED (the token is the capability): the invited friend pays without creating an account and receives a Stripe Checkout URL. Deliberately does NOT claim the seat, so no profile is created and `bookings.user_id` stays the host. Confirmation is still the verified-payment webhook. Trade-off the calling site MUST surface: with no login, only the host or the venue can cancel it afterwards. Refuses with 409 `ALREADY_CLAIMED` once someone has linked the invitation to an account.
GUEST-INVITE-01 — the class filled up before the invited friend accepted. ANONYMOUS-ALLOWED. An unpaid invitation never held a seat, so this is a normal outcome, not an error: the friend joins the waiting list and is NOT charged. If a spot opens, `reinviteWaitlistedGuests` sends a fresh payment link. Returns `{ position, already_on_waitlist }`.
The invited friend, now signed in, takes ownership of the guest seat and gets a Stripe Checkout URL. Claiming rebinds `bookings.user_id` to their profile (the host stays on `host_user_id`), which is what makes the spot appear in their own bookings and cancellable by them under the venue's ordinary cancellation rules. Capacity is still only taken by the verified-payment confirm RPC.
Returns the authenticated member’s appointments with the exact updated_at concurrency token required for cancellation. Supports upcoming/past direction, status, venue narrowing and cursor pagination.
Parameters, scopes and examples
Query parameters
directionstring
upcoming | pastDefault: upcoming
statusstring
Appointment status
organization_idstring
Optional venue UUID narrowing
POST/api/v1/appointmentsBearer token
Book my appointment
Creates a free, pass-covered, or pay-at-venue member appointment. Paid-at-booking appointments use the checkout endpoints below. When the venue payment mode is client_choice, omit payment_choice (or send online) to pay now — installed clients that do not send a choice stay on the paid checkout path. Send payment_choice=venue only for an unpaid create. X-Organization-ID and a stable Idempotency-Key are required; client communication follows the locked member-transactional policy rather than staff-selectable channels.
GET/api/v1/appointments/{id}Bearer token
Get my appointment
Returns one owned appointment, including its updated_at concurrency token. X-Organization-ID is required.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
DELETE/api/v1/appointments/{id}Bearer token
Cancel my appointment
Atomically cancels one owned current appointment. Current clients send the exact rendered updated_at token; a stale token returns 409 STALE_TARGET and must be refreshed. Temporarily, an installed legacy member client may omit the body and the server binds its owned row snapshot to the same atomic CAS—there is no retry-without-CAS path. X-Organization-ID and a stable Idempotency-Key are required.
Read-only preview of the consequence of cancelling one owned appointment right now. The window and fee come from the service row (services.cancellation_window_hours / cancellation_fee_amount, defaults 24 / 0) — the exact pair the cancel RPC enforces — so the number shown matches the number charged. An appointment with a paid deposit or a linked payment is blocked with blocked_reason "refund_required" rather than previewing a self-service refund; a terminal appointment is blocked "not_cancellable". Honours the optional x-organization-slug tenant scope; an appointment outside the resolved scope, or belonging to another client, returns 404.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
Response example
{
"data": {
"appointment_id": "uuid",
"can_cancel": true,
"blocked_reason": null,
"cancellation_window_hours": 24,
"is_late": true,
"will_charge": true,
"fee_amount": 250,
"currency": "DKK",
"refund_expected": false,
"message": "You are inside the venue’s cancellation window, so a late-cancellation fee applies."
}
}
GET/api/v1/appointments/quoteBearer token
Preview appointment payment policy
Returns the authenticated member’s server-authoritative concrete provider, effective service price, deposit, amount due at booking, remaining venue balance, payment timing, and payment_at_booking_mode (venue | online | client_choice). An `any` provider request resolves to one currently available provider before pricing. Optional payment_choice=online|venue is honoured only when the venue mode is client_choice; omitted choice defaults to online so older clients keep paying at booking. A configured deposit still requires the deposit online. Requires X-Organization-ID.
Parameters, scopes and examples
Query parameters
service_idstring · required
Service id
provider_idstring
Provider UUID or `any`; the response contains a concrete provider UUID
start_timestring · required
ISO appointment start
payment_choicestring
Optional online | venue. Omitted = pay now when the venue lets the client decide.
Claims a durable, tenant-bound operation before creating an account-pinned Stripe PaymentIntent. Returns PaymentSheet credentials. X-Organization-ID and a stable Idempotency-Key are required.
Parameters, scopes and examples
Exact live slot and provider selection. provider_id may be a concrete UUID or "any"; the server freezes one available provider and its effective price before payment.
Retrieves the exact account-scoped PaymentIntent, requires processor status succeeded, rechecks live policy, creates the appointment idempotently, and atomically links payment/accounting. Slot conflicts are compensated with an idempotent refund; 202 finalizing states are safe to retry. The Stripe webhook uses the same reconciler.
Atomically resolves all selected resources within the API-key venue, updates independent class/workshop allowance buckets, and reconciles active participants.
Add a paid-claim website applicant to a managed course roster
Trusted server-to-server bridge for venue application forms. Resolves the API-key tenant, the pass type's managed course, the applicant client/membership, and an optional localized track name; then creates or annotates an active roster enrollment and books its upcoming course sessions. Self-reported paid_deposit/paid_full values are retained as claims requiring reconciliation and never fabricate or overwrite BookingBible payment ledger state. API-key only (write:members), rate-limited, Idempotency-Key required.
Pay for a course enrollment (early-bird-aware price, or the deposit when required). Requires an Idempotency-Key header and returns a Stripe PaymentIntent client_secret + customer_id + ephemeral_key + stripe_account_id for the Payment Sheet. The enrollment is created `unpaid`; on `payment_intent.succeeded` it flips to paid/deposit_paid and its sessions are booked (deduped on the payment-intent id). Gated on membership + venue legal docs. Member-JWT. COURSE-SUITE — the body additionally accepts optional `plan` (payment-plan id), `purchaser_type` (`individual`|`company`), and `company` details (name/VAT/address) for VAT-by-purchaser + debtor invoicing. A supplied plan must exactly match a currently offered server-side plan; only an omitted property uses legacy/default behavior. The GET `/api/v1/courses/{id}` course detail additionally returns a `staff` array — `[{ role, name, title_label, photo_url, show_on_landing_page }]` — for the landing-page teaching team (COURSE-SUITE-02 multi-trainer). CV3-03 — the GET detail also returns `payment_plans` (`{ plans: [{ id, kind, installment_count? }], collection_method }`, the normalized plan OPTIONS this purchase route accepts as `plan`) and, for an authenticated Bearer caller with an enrollment, `viewer_enrollment` (`{ id, enrollment_status, payment_status, payment_plan, amount_paid, total_amount, balance, installments: [{ installment_number, amount, due_date, status }] }`; the response is always `Cache-Control: private, no-store`).
Revenue, bookings, attendance, 30-day active clients, and average revenue per client — per brand for the given period (default last 30 days). Uses bookings.brand_id and payments.brand_id populated by HYC_2. Returns venue-wide (unbranded) totals alongside the brand rows.
Parameters, scopes and examples
Required scopes
read:reports
GET/api/v1/admin/dashboard/todayBearer or API key
Today at a glance
Today's class timeline with booking counts, check-in status, and room assignments.
Parameters, scopes and examples
Required scopes
read:schedule
GET/api/v1/admin/scheduleBearer or API key
Admin schedule
Full schedule view with internal data: per-status booking counts, notes, cancellation reasons, updated_at concurrency tokens, and fail-closed historical capabilities. include_historical=true requires scheduling.manage_history.
Parameters, scopes and examples
Required scopes
read:schedule
Query parameters
start_datestring
Inclusive ISO date/time lower bound
end_datestring
Inclusive ISO date/time upper bound
include_historicalstring
Include protected historical class rows; requires scheduling.manage_historyDefault: false
GET/api/v1/admin/appointmentsBearer token
Venue appointment schedule
Business-app venue-wide appointment list with updated_at concurrency tokens and authoritative, fail-closed historical capabilities. Filters by ISO window, direction, status, provider, and location. Permission: bookings.manage.
Parameters, scopes and examples
Query parameters
fromstring
Inclusive ISO start time
tostring
Exclusive ISO end time
directionstring
upcoming | pastDefault: upcoming
statusstring
Appointment status
provider_idstring
Provider UUID
location_idstring
Location UUID
limitnumber
Maximum 200Default: 100
POST/api/v1/admin/appointmentsBearer token
Create an appointment for a client
Creates a tenant-bound current/future appointment for a known member or contact-complete guest through the canonical atomic appointment engine. Venue-local past dates and historical attestation fields fail closed until the dedicated executor is installed. Permission: bookings.manage. Idempotency-Key required. Client delivery is default-silent: only an explicit notification_channels selection of email, sms, and/or push can send. A non-empty selection requires notifications.send and an authoritative availability preflight before the mutation; an unavailable channel fails without creating the appointment. Omitted or empty channels and legacy notify booleans remain silent.
Tenant-bound client, provider, service, location, payment, notes, lifecycle state, updated_at concurrency token, and authoritative fail-closed historical capabilities for the Business app. Permission: bookings.manage.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
PATCH/api/v1/admin/appointments/{id}Bearer token
Operate an appointment
Atomic ordinary check-in, start, complete, no-show, cancel, or reschedule with the exact expected_updated_at token returned by GET. A stale token returns 409 STALE_TARGET without mutation. Each action is checked against its canonical permission. Past/terminal appointments, past reschedule targets, and historical attestation fields fail closed until the dedicated executor is installed. Idempotency-Key required. No-show, cancel, and reschedule are default-silent and accept an explicit notification_channels selection of email, sms, and/or push; a non-empty selection requires notifications.send and an authoritative availability preflight before mutation. An unavailable channel fails without changing the appointment. Omitted or empty channels and legacy notify booleans remain silent. Check-in, start, and complete are non-client-contact actions and reject notification_channels.
Parameters, scopes and examples
Path parameters
idstring · required
Appointment UUID
Discriminated appointment action with the opaque updated_at token returned by the appointment detail
Dedicated, atomic appointment-history command contract. Requires a UUID Idempotency-Key, appointments.manage_history plus the ordinary operation permission, REWRITE attestation, and a past effective_at. Existing-row operations require the exact expected_updated_at and expected_status returned by the appointment detail; retrocreate accepts only the closed non-financial appointment intent. Corrections are always silent and reject notification controls. The route returns 503 HISTORICAL_EXECUTOR_UNAVAILABLE without table-call fallback until the separately reviewed correct_appointment_historical database RPC is installed.
Parameters, scopes and examples
Required scopes
appointments.manage_history
Path parameters
idstring · required
Appointment UUID
Closed appointment correction; history_confirmation_token must be REWRITE
Tenant-bound class and appointment reviews for the Business app. Supports source, visibility, rating, and pagination filters. Anonymous reviewer identity is never returned. Permission: feedback.view.
Returns the consent-, preference-, contact-, and suppression-aware email/SMS reach for a venue-scoped marketing audience. Permission: marketing.flash_sales.
Returns canonical refundable headroom, payer receipt contacts, SMS availability with an explicit disabled reason, original card brand/last4, venue refund destinations, and eligibility. Native clients must use this response instead of deriving refund options locally.
Creates a venue-scoped promo and public offer, optionally dispatching a consent-gated email/SMS campaign. Idempotency-Key required. Permission: marketing.flash_sales.
Explains current automatic review-request rules and returns anonymized recent delivery outcomes. Permission: marketing.reviews.
GET/api/v1/admin/sites/statusBearer token
Website status snapshot
Returns the org-scoped venue website summary for the Business app: site identity, draft/published versions, preview URL, publish-readiness blockers/warnings, and connected custom-domain verification/SSL state. Permission: sites.view.
Parameters, scopes and examples
Required scopes
sites.view
POST/api/v1/admin/sites/publishBearer token
Publish the venue website
Publishes one tenant-bound website through the canonical publish core. Requires sites.publish plus a stable Idempotency-Key. Returns readiness blockers when the draft is not yet publishable; older mobile builds may ignore additive warnings.
Parameters, scopes and examples
Required scopes
sites.publish
Tenant-scoped website publish request
Request body
{
"site_id": "00000000-0000-4000-8000-000000000001",
"note": "Published after mobile review"
}
POST/api/v1/admin/sites/ai/chatBearer token
Talk to the website builder AI
Business-app SSE transport for the org-scoped website builder assistant. Requires sites.manage. Returns the mobile AI event vocabulary over Server-Sent Events and adds `site_patch` events so clients can refresh status mid-turn.
Parameters, scopes and examples
Required scopes
sites.manage
Tenant-bound site-builder message
Request body
{
"site_id": "00000000-0000-4000-8000-000000000001",
"conversation_id": null,
"message": "Make the homepage warmer and highlight workshops.",
"attachment_ids": [
"00000000-0000-4000-8000-000000000002"
]
}
POST/api/v1/admin/sites/attachmentsBearer token
Upload a website-builder attachment
Multipart upload for the Business website builder chat. Requires sites.manage. The file is stored through the shared AI attachment pipeline and later referenced by `attachment_ids` on the site chat route.
Parameters, scopes and examples
Required scopes
sites.manage
DELETE/api/v1/admin/sites/attachmentsBearer token
Delete a pending website-builder attachment
Deletes one tenant-owned, not-yet-bound website-builder attachment before it is sent in chat. Requires sites.manage.
Creates, replaces, or removes the one automatic clips-empty offer for a limited recurring pass or still-valid class pack. The target may be hidden from public catalogs. Permission: passes.manage.
Returns every active venue pass type for authenticated POS staff, including pass types intentionally hidden from public consumer catalogs. Permission: pos.access.
Business-app stream-control DTO for one tenant-bound class instance. Returns source options without provider live-stream ids, stream keys, RTMP URLs, SRT URLs, or playback URLs; action availability includes exact disabled reason codes. Visible to venue schedule/check-in readers and assigned staff roster readers. Source/go-live writes repeat module/settings gates; end remains available for safe live shutdown.
Sets or clears the occurrence-level stream source before the class goes live. Requires class.create, active streaming module/entitlement, a streamable class, an active RTMP/SRT source with an attached provider stream, tenant binding, lifecycle CAS status=scheduled, UUID Idempotency-Key, and no assigned-instructor owner-toggle block. The operation is silent; notification fields are rejected.
Starts a class stream from an existing class provider stream or an active selected RTMP/SRT source. Requires class.create, active streaming entitlement/module, streaming settings enabled, streamable class, venue-local class date, tenant binding, lifecycle CAS status=scheduled, provider-adapter enablement, UUID Idempotency-Key, and no assigned-instructor owner-toggle block. Provider enablement is compensated when the DB transition fails or loses a race unless the winner uses the same stream. The route does not mint new one-time provider streams or expose source credentials; it is operationally silent and rejects notification fields.
Ends a live class stream. Requires class.create, tenant binding, lifecycle CAS status=live, and UUID Idempotency-Key. The class completion commits before the shared-stream provider disable guard runs; the response reports provider_stop as disabled, skipped_shared, failed, or not_applicable. The route records streaming usage after the class completion commit. It is operationally silent and rejects notification fields.
Retries only the provider disable step after a class has already completed; it never re-completes the class or repeats lifecycle effects. Requires class.create, tenant binding, UUID Idempotency-Key, and an attached provider stream. The shared-stream guard is organization-scoped and no blocking occurrence identifier is returned. This route is operationally silent and rejects notification fields.
PHONE-PUBLISH-01: mints an ephemeral, class-scoped provider live stream plus a hashed single-use claim token, bound to one organization, one class occurrence, and the preparing user, with a short server-enforced TTL. Requires class.create OR the assigned instructor when the venue enables instructor go-live, active streaming module/entitlement, streamable class, venue-local class date, the phone_publisher_sessions kill switch, tenant binding, and a UUID Idempotency-Key. Returns non-secret session state and the one-time claim token; NEVER ingest URLs, stream keys, or provider resource ids. One active session per class; supersession refuses while another device is actively publishing with a fresh heartbeat.
PHONE-PUBLISH-01: atomically consumes the single-use claim token and returns short-lived RTMPS ingest material exactly once (Cache-Control: private, no-store). Only the session creator may claim. Deliberately NOT idempotency-cached — a duplicate claim returns CLAIM_ALREADY_USED and the recovery path is revoke + prepare a new session; the old secret is never re-displayed. No ingest material is ever stored server-side.
PHONE-PUBLISH-01: transitions the claimed session to publishing and returns the authoritative session/provider/class status snapshot. Never marks the class live — only the provider active webhook does. Owner-bound, tenant-bound, UUID Idempotency-Key required.
PHONE-PUBLISH-01: periodic liveness touch returning session state, provider connection status (ingest fields stripped), and class lifecycle status. When the provider confirms an active input and the class is still scheduled inside the phone-publisher window, the snapshot reconciles the class to live (CAS; the cron sweep is the backstop). Owner-bound and naturally idempotent, so no Idempotency-Key is required. A stale heartbeat makes a publishing session eligible for takeover by another authorized device.
PHONE-PUBLISH-01: ends the active phone publisher session, completes the class when this session took it live (usage recorded after the completion commit), and records a DURABLE provider-cleanup outcome — a failed teardown is surfaced in GET state and retried, never hidden. Requires class.create or the permitted assigned instructor, tenant binding, and a UUID Idempotency-Key.
PHONE-PUBLISH-01: revokes a session whose device was lost or reinstalled or should no longer publish. The provider stream is disabled and scheduled for deletion, killing any leaked ingest material; a fresh session must be prepared and claimed — the old secret is never re-displayed. Requires class.create or the permitted assigned instructor, tenant binding, and a UUID Idempotency-Key.
PHONE-PUBLISH-01: explicitly retries a failed or pending provider teardown for a terminal publisher session. Requires class.create or the permitted assigned instructor, tenant binding, and a UUID Idempotency-Key.
Parameters, scopes and examples
Required scopes
class.create
Path parameters
classInstanceIdstring · required
Class instance UUID
PATCH/api/v1/admin/schedule/{id}Bearer or API key
Edit class instance
Update start/end time, instructor, class type, capacity, or room on a single class instance. Capacity can never go below the current booked count (422 CAPACITY_BELOW_BOOKED — cancel bookings first; no force override). Instructor/room changes are conflict-checked; instructor must be qualified. Notifications default silent: omitted controls and legacy notify_attendees never send. An explicit notify audience plus channel sends the branded schedule-change email/SMS/push to participants and/or instructors on time/instructor/room changes and requires notifications.send. Idempotency-Key honored; audit_log carries per-field from/to diffs.
Atomic, immutable-ledger correction for an isolated past class. Requires a UUID Idempotency-Key, scheduling.manage_history plus scheduling.manage, expected_updated_at and expected_status for an existing row, a past effective_at, and typed REWRITE attestation. Cancellation-state corrections additionally require class.cancel. Classes with roster, financial, course, workshop, import, streaming, or other linked records fail closed for specialist review. Notifications are always silent.
Parameters, scopes and examples
Required scopes
scheduling.manage_history
Path parameters
idstring · required
Class instance ID
Bounded historical class-instance correction
Request body
{
"operation": "class_instance.correct_timing",
"expected_updated_at": "2026-08-20T09:00:00.000Z",
"expected_status": "completed",
"history_reason": "Signed instructor log confirms the recorded class time",
"history_confirmation_token": "REWRITE",
"effective_at": "2026-08-20T10:00:00.000Z",
"intent": {
"startTime": "2026-08-20T08:00:00.000Z",
"endTime": "2026-08-20T09:00:00.000Z"
}
}
Atomic, immutable-ledger correction for a past recurring availability window. Requires a UUID Idempotency-Key, availability.manage_history, staff_portal.availability, staff.edit for another staff member, expected_updated_at plus expected_is_active for existing rows, a past effective_at, and typed REWRITE attestation. The staff path and tenant-owned row pin ownership. Notifications are always silent.
Applies explicit venue-local start/end time, room, instructor, capacity, or class type to 1–50 tenant-owned classes with per-row conflict/failure results. Notifications default silent; an explicit notify audience plus channel requires notifications.send and sends only after each successful write. Idempotency-Key required.
Cancels 1–50 tenant-owned classes through the canonical cancellation engine with per-row results. Notifications default silent: omission and legacy notify_attendees never send. Explicit notify audience plus channel requires notifications.send; clients support Email/SMS/Push and instructors support Email/SMS. Push without a selected client audience returns 422. Idempotency-Key required.
POST/api/v1/admin/schedule/{id}/cancelBearer or API key
Cancel class
Cancel a class instance (bookings cancelled, clips restored, audit + webhook). Notifications default silent: omission and legacy notify_attendees never send. Explicit notify.{audience,channels} requires notifications.send; channel overrides (email/sms/push) AND with client preferences. Clients support Email/SMS/Push; instructors support Email/SMS, and Push without a selected client audience returns 422. Mixed client+instructor Email/Push notifies clients by Email/Push and instructors by Email. Idempotency-Key honored.
Parameters, scopes and examples
Required scopes
write:schedule
Path parameters
idstring · required
Class instance ID
POST/api/v1/admin/schedule/{id}/substituteBearer or API key
Assign substitute
Replace instructor for a class. Validates no scheduling conflicts across locations. Notifications default silent. Explicit notify audience plus channel requires notifications.send; client delivery is Push-only and substitute-instructor delivery is Email-only; selecting both audiences with Email+Push sends those exact legs. SMS or a channel without its supported audience returns 422. Idempotency-Key honored.
Parameters, scopes and examples
Required scopes
write:schedule
Path parameters
idstring · required
Class instance ID
GET/api/v1/admin/checkinBearer or API key
Venue-local check-in day strip
The venue-local day's classes for the native staff check-in screen (Business app): per-class check-in/waitlist counts, room/instructor, and the day-navigation gates (today vs. read-only past/future). Defaults `date` to the venue-local today when omitted; optional `location_id` (query param or X-Location-ID header) narrows to one location.
Parameters, scopes and examples
Required scopes
read:bookings
Query parameters
datestring
Venue-local date, YYYY-MM-DD. Defaults to the venue-local today.
location_idstring
Restrict results to one location. Also accepted as the X-Location-ID header.
GET/api/v1/admin/checkin/{classInstanceId}Bearer or API key
Attendee list
Class roster with member details, pass info, add-ons, included services, check-in status, and class/booking updated_at concurrency tokens. Whole-class cancellations retain the preserved roster and each attendee’s previous status; ordinary client cancellations remain excluded.
Parameters, scopes and examples
Required scopes
read:bookings
Path parameters
classInstanceIdstring · required
Class instance ID
Query parameters
include_historical_recordsstring
Include protected cancelled/late-cancelled roster rows; requires scheduling.manage_historyDefault: false
Send a bulk email or SMS to a selected subset of one class instance. Submitted booking_ids are intersected server-side with the organization's active or whole-class-preserved roster; ordinary cancellations and stale/foreign ids are dropped and counted as skipped. Caller-supplied contact data is never accepted. Uses the canonical consent/suppression-aware bulk senders and requires the can_view_client_contact_info membership toggle. Idempotency-Key is honored.
Parameters, scopes and examples
Required scopes
members.contact
Path parameters
classInstanceIdstring · required
Class instance UUID
Channel, roster booking ids, and message
Request body
{
"channel": "email",
"booking_ids": [
"00000000-0000-4000-8000-0000000000b1"
],
"subject": "Class update",
"message": "Hi {{first_name}} — here is an update about your class."
}
POST/api/v1/admin/checkin/{classInstanceId}/{bookingId}Bearer or API key
Check in member
Check a member into class. Validates late arrival cutoff.
Parameters, scopes and examples
Required scopes
write:checkin
Path parameters
classInstanceIdstring · required
Class instance ID
bookingIdstring · required
Booking ID
POST/api/v1/admin/checkin/{classInstanceId}/{bookingId}/noshowBearer or API key
Mark no-show
Mark member as no-show. Applies no-show fee if configured.
Parameters, scopes and examples
Required scopes
write:checkin
Path parameters
classInstanceIdstring · required
Class instance ID
bookingIdstring · required
Booking ID
GET/api/v1/admin/membersBearer or API key
List members
Membership-driven client list with exact pre-pagination status and pass filtering. Search by name, email, phone or venue client ID; optionally filter by tag, active pass type, or canonical pass family. pass_type_id and pass_family combine with AND semantics. Every successful response, including zero-match pages, includes meta.pass_type_options and meta.pass_family_options. Options expose distinct active-client counts across the full authenticated venue before pagination; pass types include current active templates plus archived templates still held by active clients, including types hidden from public pricing and course/workshop-managed types.
Parameters, scopes and examples
Required scopes
read:members
Query parameters
searchstring
Search by name, email, or phone
statusstring
Client status: active, inactive, new, or no_pass
tagstring
Filter by member tag
pass_type_idstring
Filter by active pass type
pass_familystring
Filter by pass family: recurring, class_pack, time_based, or intro_offer
Register an active client or send a pending client invitation. Enforces the venue plan limit, requires members.edit and an Idempotency-Key, and records a PII-safe audit event.
Full member profile: passes with course-fulfillment provenance, canonical native course_access, recent bookings/payments, tags, scores, credits, referrals, plus server-authoritative total_bookings and last_visit_at, per-channel notification_availability (email/SMS/push with exact unavailable reasons), and contact_details_visible (contact fields are nulled unless the caller holds members.contact and membership contact visibility).
Soft-deactivates only the active membership at the selected venue; it never deletes the shared profile or changes memberships at other venues. Delivery is silent by default. An explicit notify object may select Email, SMS, and/or Push, which requires notifications.send and an availability preflight before the deactivation commits. A post-commit delivery failure is returned separately as notification_failure and never restores access. Protected Admin/Finance memberships retain their shared lifecycle authorization checks. Idempotency-Key required. Permission: members.delete.
Parameters, scopes and examples
Required scopes
members.delete
Path parameters
idstring · required
Member user ID
Deactivation reason and optional explicit client delivery channels
Tenant-scoped pass history with an exact total and opaque keyset cursor. Returns up to 100 records per page and never exposes processor subscription identifiers.
Deterministically merges live bookings and imported historical visits. Historical rows carry record_source=migration_history and read_only=true. The total is exact across both stores.
Parameters, scopes and examples
Required scopes
members.view_insights
Path parameters
idstring · required
Active member ID
Query parameters
limitinteger
Items per page (1–100)Default: 25
afterstring
Opaque next_cursor from the previous page
pass_idstring
Only bookings funded by this pass
cycle_startstring
Venue-local YYYY-MM-DD start of a pass usage cycle (inclusive)
cycle_endstring
Venue-local YYYY-MM-DD end of a pass usage cycle (exclusive)
Tenant-scoped payments with exact total, refunds, safe card display, invoice linkage, and explicit receipt capabilities. Processor IDs, client secrets, and raw receipt URLs are never returned.
Re-sends through the canonical POS sender to the member contact stored on the server. Only same-venue POS-backed receipt payments are eligible; arbitrary recipients and payment retry are not supported.
Parameters, scopes and examples
Required scopes
notifications.send
Path parameters
idstring · required
Active member ID
paymentIdstring · required
Same-venue payment ID
Receipt delivery channel advertised by the payment receipt capability
Request body
{
"method": "email"
}
GET/api/v1/admin/paymentsBearer token
Org-wide recent sales
Business-app contract C6: the venue's recent payments (all statuses), newest first, mirroring the web sales drawer rows — plain-language method label, card label, money bucket (captured | recorded | internal), and the drawer's refund-offer rule (`refundable` = settled non-guest rows with money remaining). Amounts are integer minor units (øre). Cursor-paginated (opaque keyset cursor), limit ≤ 50. Range resolves in the venue's timezone.
Business-app contract C7: executes a claimed review through canonical processRefund. Body { review_intent_id, confirmation?, amount?, reason?, client_receipt_comment?, destination_id?, method_reference?, notify_client?, receipt_channels?: ('email'|'sms'|'push')[] }. Destination and notes must match the immutable review. Email is selectable (suppression is audited). SMS works only when review context reports available; otherwise execution rejects before money moves with 422 REFUND_SMS_UNAVAILABLE and unavailable_reason. Success includes refund_id, printable bearer-authenticated PDF URL, and per-channel outcomes.
Parameters, scopes and examples
Required scopes
billing.refunds.same_daybilling.refunds.full
Path parameters
idstring · required
Payment UUID
Refund details (amount in MAJOR units)
Request body
{
"review_intent_id": "00000000-0000-4000-8000-000000000000",
"amount": 199,
"reason": "Client requested the refund",
"client_receipt_comment": "We hope to see you again soon.",
"destination_id": "original",
"notify_client": true,
"receipt_channels": [
"email",
"push"
]
}
GET/api/v1/admin/refunds/{id}/receiptBearer token
Download canonical refund receipt PDF
Bearer-authenticated, tenant-scoped, no-store PDF used by native print/share. Contains only the optional client receipt comment; the staff-only internal reason is never rendered.
Business-app contract C8: send a bulk email or SMS to participants of one class instance. Recipients are resolved server-side — the submitted booking_ids are intersected with the class's ACTIVE roster (confirmed/waitlisted/checked_in); stale ids are dropped and counted as skipped, and caller-supplied contact info is never accepted. Delegates to the same senders/consent semantics as the web check-in bulk bar (templates admin_bulk_email / admin_bulk_sms). Requires the TV-D can_view_client_contact_info membership toggle. Returns { sent, skipped }.
Parameters, scopes and examples
Required scopes
members.contact
Path parameters
classInstanceIdstring · required
Class instance UUID
Channel, roster booking ids, and the message
Request body
{
"channel": "email",
"booking_ids": [
"00000000-0000-4000-8000-0000000000b1"
],
"subject": "Tonight’s class moves to Room 2",
"message": "Hi {{first_name}} — we moved tonight’s class to Room 2. See you there!"
}
Business-app parity: the eligible one-class products for paid guest spots. Uses the same guest visitor permission and catalog core as the web check-in screen.
Business-app parity: add 1–20 guest spots as payment-link, paid-at-desk, or comp/free bookings. Payment-link delivery supports email, SMS, or both. Uses the same context-free core as web; Idempotency-Key required.
Parameters, scopes and examples
Required scopes
booking.checkin
Path parameters
classInstanceIdstring · required
Class instance UUID
Guest contact, count, payment mode, product, and delivery channels
Business-app contract C1: the venue's failed payments (payments.status='failed') in the trailing window (default 30 days), newest first, cap 100. Each row carries client + linked pass context, a plain-language method label, and `retryable` per the same pure decider the web Retry button uses. Amounts are integer minor units (øre).
Business-app contract C2: re-collect a failed payment through the canonical retry core (PaymentIntent confirm or off-session invoice pay on the SC2-resolved Connect account, driving handleInvoicePaid). Empty body. Idempotency-Key required. Returns status succeeded | requires_action | failed with a plain-language message.
Record an external settlement for a failed renewal
Business-app contract C3: the failed recurring-renewal invoice was paid through another channel (cash, bank transfer, MobilePay, external card terminal, other). Settles the Stripe invoice out-of-band so the canonical recovery reactivates the pass, attributing the recovered payments row to the real method. amount is integer minor units (øre). Idempotency-Key required.
Parameters, scopes and examples
Required scopes
passes.manage
Path parameters
paymentIdstring · required
Failed payment UUID
Settlement details
Request body
{
"method": "bank_transfer",
"amount": 79900,
"paid_at": "2026-07-31",
"note": "Paid via bank transfer, ref 1234",
"notify_client": true
}
Business-app contract C4: comp the failed recurring-renewal cycle — the client keeps the period, 0 revenue is recorded (the recovered payments row is forced to 'comped' amount 0). Reason required. Idempotency-Key required.
Parameters, scopes and examples
Required scopes
passes.manage
Path parameters
paymentIdstring · required
Failed payment UUID
Waive details
Request body
{
"reason": "Goodwill — studio closure week",
"notify_client": true
}
Business-app contract C5: venue-imposed suspension (distinct from the member freeze) — blocks bookings until unsuspended. Client delivery is silent by default and accepts only notify.audience.clients=true plus an explicit Email/SMS/Push selection; legacy notify_client/notify_channels inputs remain silent. A non-empty selection requires notifications.send, and an unavailable selected channel returns PASS_NOTIFICATION_CHANNEL_UNAVAILABLE before the pass changes. Idempotency-Key (UUID) required; replay returns the stored response and the stable delivery reference prevents re-sending. Delivery failure after the pass write is reported as notification.sent=false and never rolls the suspension back.
Parameters, scopes and examples
Required scopes
passes.manage
Path parameters
passIdstring · required
Pass UUID
Optional reason and explicit, default-silent client notification choice
Business-app contract C5: lift a venue-imposed suspension. Body is optional and silent by default. Client delivery requires notify.audience.clients=true, an explicit Email/SMS/Push selection, and notifications.send; legacy booleans/arrays remain silent. An unavailable selected channel returns PASS_NOTIFICATION_CHANNEL_UNAVAILABLE before the pass changes. Idempotency-Key (UUID) required; replay never re-sends. A post-write delivery failure returns notification.sent=false without rolling the pass change back. 422 NOT_SUSPENDED for a pass that is not suspended.
Business-app contract C5 (PASS-REACTIVATE-01): flip an expired/cancelled NON-recurring pass back to active; a run-out window requires new_end_date ≥ venue-local today. Client delivery is silent by default and requires notify.audience.clients=true, explicit Email/SMS/Push channels, and notifications.send; legacy notification inputs remain silent. Unavailable channels reject before mutation. Idempotency-Key (UUID) required and replay never re-sends; delivery failure after the write returns notification.sent=false without rollback. Recurring memberships are refused (422 RECURRING_UNSUPPORTED) — restart via a real re-mint. Audit pass_reactivated + reverse_payload.
Business POS read for an active venue client. Returns sanitized card references only (brand, last4, expiry, default, expired, chargeable); imported display-only cards are explicitly non-chargeable. Requires the canonical pos.access permission. Never returns customer IDs, processor metadata, full card data, or client secrets.
Business POS card-setup operation for an active venue client. Requires an in-person consent attestation and Idempotency-Key. Returns the SetupIntent client secret, exact Stripe account namespace, legal merchant country, and frozen regional revision for native Payment Sheet.
Update the member phone number after an explicit staff confirmation. Requires members.edit and writes an audit record.
Parameters, scopes and examples
Required scopes
write:members
Path parameters
idstring · required
Member user ID
Supported member profile fields
Request body
{
"phone": "+4512345678"
}
POST/api/v1/admin/members/{id}/creditsBearer or API key
Issue account credit
Grant account credit to an active member (positive manual adjustment) on the same atomic, organization-scoped ledger path as the web action. The response balance is the canonical venue-available balance; profiles.credit_balance is maintained only as an account-wide compatibility cache. Currency must equal the venue currency (422 CURRENCY_MISMATCH). Client delivery is silent by default and requires an explicit canonical Email/SMS/Push selection plus notifications.send; membership and unavailable selected channels are rejected before the balance changes, and legacy booleans remain silent. Idempotency-Key is required (1–255 characters): an identical retry returns the original transaction and balance, while reuse for a different semantic request returns 409 IDEMPOTENCY_KEY_REUSE_MISMATCH.
Venue-wide booking list with filtering by date, status, class, member, and location.
Parameters, scopes and examples
Required scopes
read:bookings
Query parameters
fromstring
Start date (YYYY-MM-DD)
tostring
End date (YYYY-MM-DD)
statusstring
Filter by booking status
class_instance_idstring
Filter by class instance
user_idstring
Filter by member
location_idstring
Filter by location
POST/api/v1/admin/bookingsBearer or API key
Book for member
Create a confirmed or waitlisted booking on behalf of a member. Supports capacity override for admins. Client delivery is silent by default and requires an explicit Email/SMS/Push selection plus notifications.send; unavailable selected channels are rejected before booking/pass/count effects. The engine automatic notice is suppressed for this admin route so omission cannot send.
POST/api/v1/admin/bookings/waitlistBearer or API key
Add member to waitlist
Manually place a member on a class's waitlist at the queue tail. Always creates a waitlisted booking (never auto-confirms). Client delivery is default-silent and requires both an explicit client audience/channel selection and notifications.send; unavailable selected channels are rejected before queue effects.
DELETE/api/v1/admin/bookings/waitlist/{bookingId}Bearer or API key
Remove member from waitlist
Remove a waitlisted booking. Waitlisted rows only (409 on a confirmed booking); never triggers auto-promotion. Idempotent. Client delivery is default-silent and requires both an explicit client audience/channel selection and notifications.send; unavailable selected channels are rejected before queue effects.
Parameters, scopes and examples
Required scopes
write:bookings
Path parameters
bookingIdstring · required
Waitlisted booking ID
Optional reason and explicit client notification channels. Omit notify to stay silent.
POST/api/v1/admin/bookings/{bookingId}/cancelBearer or API key
Cancel a confirmed booking
Cancel a member's confirmed booking on their behalf (admin cancel semantics — may charge late fees + restore clips per policy; NOT the fee-free lapsed-booking path). Decrements booked_count, writes audit + booking.cancelled webhook, and issues a 30s undo ticket. Client delivery is silent by default and requires an explicit Email/SMS/Push selection plus notifications.send; unavailable selected channels are rejected before any mutation; legacy notify_client remains silent. Idempotent via Idempotency-Key. Returns 409 ALREADY_CANCELLED on a cancelled booking and 409 ON_WAITLIST for a waitlisted row (use the waitlist remove endpoint).
Bearer-JWT only. Correct one past class booking through the protected, organization-scoped historical ledger. Requires scheduling.manage_history plus the ordinary operation permission (bookings.manage for retrocreate, booking.checkin for attendance, booking.checkin + bookings.mark_no_show for no-show, or booking.cancel_member for cancellation/invalidation). Idempotency-Key must be a UUID. expected_class_updated_at is a compare-and-set token mandatory for every operation; expected_updated_at is a compare-and-set token additionally required for existing-booking operations. The executor refuses linked financial, pass, guest, waitlist, external, and other unsafe effects rather than inventing compensating semantics. Historical correction delivery is explicitly default-silent: Email, SMS, and Push are not available for this operation; a canonical explicit selection first requires notifications.send and then returns 422 before any mutation. Until the protected database executor has been installed, the route returns 503 HISTORICAL_EXECUTOR_UNAVAILABLE and never substitutes table calls.
Parameters, scopes and examples
Required scopes
scheduling.manage_history
Path parameters
bookingIdstring · required
Class booking ID
One closed class-booking correction. Every operation requires expected_class_updated_at; existing-booking operations also require expected_updated_at. history_confirmation_token must be REWRITE.
Bearer-JWT, passes.manage-scoped server-authoritative preview for a recurring membership. Resolves the selected client and saved card in the active venue, validates the venue-local start-date policy, and returns canonical buyer-specific gross pricing, registration fee/waiver, due-today amount, access date, first charge, next renewal, card label, contract/terms summary, and — when an operator discount schedule is requested — the resolved discount_schedule block with the agreed amount, the number of discounted periods and the first full-price charge date. This endpoint never mutates or charges.
Parameters, scopes and examples
Required scopes
passes.manage
Recurring membership options with exactly one of saved_payment_method_id (card-collected) or external_tender_method (venue-collected renewals, billing_mode=external). Optional registration_fee_discount applies a per-sale percentage discount to the one-time registration fee; legacy waive_registration_fee remains accepted. Optional discount_schedule sets an operator-agreed price for the first period, a fixed number of periods, or for as long as the membership runs.
Bearer-JWT, passes.manage-scoped recurring membership creation through the canonical subscription checkout core. Idempotency-Key is required. Re-resolves pricing, dates, saved-card ownership, Stripe locality, VAT/age band, concessions, and legal delivery before mutation. Returns the exact preview plus pass/subscription ids, payment status, and contract-delivery result. Off-session declines and SCA requirements are explicit 402 responses.
Parameters, scopes and examples
Required scopes
passes.manage
The same server-authoritative options accepted by the preview endpoint
Bearer-JWT, passes.manage-scoped option list for an organization-owned pass. Each option is buyer-priced by the canonical membership-change quote engine; a failed target is reported separately and cannot hide valid sibling options. Query: pass_id.
Parameters, scopes and examples
Required scopes
passes.manage
GET/api/v1/admin/memberships/changeBearer token
Preview a client membership change
Bearer-JWT, passes.manage-scoped server quote. Query: pass_id, target_pass_type_id and optional override_price_major. Returns exact charge, credit, effective date, next renewal and a short-lived signed quote binding; it never mutates or charges.
Parameters, scopes and examples
Required scopes
passes.manage
POST/api/v1/admin/memberships/changeBearer token
Apply a client membership change
Bearer-JWT, passes.manage-scoped confirmation through the canonical membership-change core. Requires Idempotency-Key and the exact signed quote returned by preview; foreign-venue passes resolve as not found and client-supplied prices are not accepted.
Process an idempotent point-of-sale transaction. Supports cash, venue credit, and a server-validated saved card. Saved-card SCA returns a 202 challenge response and is completed with a separate idempotent finalize request. Fresh cards, MobilePay and Stripe Terminal use their dedicated flows.
Recent POS transactions filtered by location and date. Refund headroom subtracts both succeeded and in-flight operation claims; refunded_amount reports succeeded claims and pending_refund_amount reports the reserved in-flight amount.
Parameters, scopes and examples
Required scopes
read:payments
POST/api/v1/admin/pos/transactions/{id}/receiptBearer or API key
Resend POS receipt
Resend a tenant-scoped POS transaction receipt by email or SMS. Uses the client's stored contact unless an explicit recipient is supplied. Idempotency-Key is required and retries of the same delivery action must reuse it.
Parameters, scopes and examples
Required scopes
write:pos
Path parameters
idstring · required
POS transaction ID
Receipt delivery channel and optional recipient override
Request body
{
"method": "email"
}
GET/api/v1/admin/pos/summaryBearer or API key
Daily POS sales summary
Daily sales breakdown for the given date (default today): totals (gross/discounts/VAT/credits/net) plus per-payment-method and per-transaction-type buckets. Completed transactions only; same date-window semantics as /admin/pos/recent.
Parameters, scopes and examples
Required scopes
read:payments
Query parameters
datestring
YYYY-MM-DD (default today)
location_idstring
Filter by location
GET/api/v1/admin/dashboard/revenue-seriesBearer or API key
Daily revenue series (sparkline)
Zero-filled daily revenue series ending today — succeeded payments bucketed by UTC day, matching the dashboard revenue_today semantics. days clamps to 1–90 (mobile uses 7 and 30).
Parameters, scopes and examples
Required scopes
read:reports
Query parameters
daysinteger
Window length in days (1–90)Default: 7
POST/api/v1/admin/members/{id}/membership/pauseBearer or API key
Pause membership
Pause (freeze) a member’s pass for a date window. Validated against the pass type’s pause policy; recurring memberships receive exact per-cycle billing credits on their own Stripe account; audit_log pass_paused. Client delivery is silent by default and requires notify.audience.clients=true plus explicit Email/SMS/Push channels and notifications.send. Legacy notification booleans remain silent. Selected-channel availability is rechecked before mutation; exact unavailable/preflight-failed responses leave the membership unchanged. Idempotency-Key honored. {id} accepts UUID or display ID (e.g. HYC-0042).
POST/api/v1/admin/members/{id}/membership/resumeBearer or API key
Resume membership
Resume a paused pass (Stripe-first ordering with compensating re-pause). Audit_log pass_resumed. Client delivery is silent by default and uses only an explicit canonical Email/SMS/Push selection. Selected-channel availability is rechecked before mutation; exact unavailable/preflight-failed responses leave the membership unchanged. Idempotency-Key honored.
Parameters, scopes and examples
Required scopes
write:members
Path parameters
idstring · required
Member user ID or display ID
Resume immediately or from a venue-local date. An unproven Stripe pause stays blocked unless acknowledge_unproven_pause types CLEAR PAUSE plus a reason. Optional explicit client delivery.
POST/api/v1/admin/members/{id}/membership/terminateBearer or API key
Cancel / terminate membership
Cancel or terminate a recurring membership with explicit effective dates: mode period_end (cancel at current cycle end), chosen_cycle (kth upcoming cycle, cycle required), or immediate. Runs the kill-switch-gated termination engine (fail-closed Stripe). Response carries the engine-confirmed effective_at. Client delivery is silent by default and requires an explicit canonical channel choice plus notifications.send; legacy booleans remain silent. Selected-channel availability is rechecked before mutation; exact unavailable/preflight-failed responses leave the membership unchanged. Idempotency-Key honored.
GET/api/v1/admin/members/{id}/membership/termination-previewBearer or API key
Termination preview (cycle picker)
Next 6 cycle boundaries (effective_at, venue-local last usable day, precedes-binding flag), venue policy defaults, and billing horizon for the terminate endpoint’s cycle picker.
Parameters, scopes and examples
Required scopes
read:members
Path parameters
idstring · required
Member user ID or display ID
Query parameters
pass_idstring
Pass ID (uuid)
POST/api/v1/admin/terminal/connection-tokenBearer or API key
Stripe Terminal connection token
Mint a Stripe Terminal connection token plus the venue Terminal location id (`{secret, location_id}`) for card-present readers and Tap-to-Pay. Ephemeral-token fetch — no Idempotency-Key (the Terminal SDK always needs a fresh token).
Parameters, scopes and examples
Required scopes
write:pos
POST/api/v1/admin/terminal/payment-intentBearer or API key
Create Terminal payment intent
Create a card-present PaymentIntent (manual capture) on the venue connected account. Returns `{client_secret, payment_intent_id}`. Money mutation — send an Idempotency-Key; replays return the cached response and the key is forwarded to Stripe.
Parameters, scopes and examples
Required scopes
write:pos
Payment intent
Request body
{
"amount": 12000,
"currency": "DKK"
}
POST/api/v1/admin/terminal/captureBearer or API key
Capture Terminal payment
Capture a confirmed card-present PaymentIntent. Returns `{captured: true, payment_intent_id}`. Money mutation — send an Idempotency-Key; an already-captured intent returns success.
Parameters, scopes and examples
Required scopes
write:pos
Capture
Request body
{
"payment_intent_id": "pi_xxx"
}
POST/api/v1/admin/terminal/receiptBearer or API key
Send Terminal receipt
Email or SMS a receipt for a captured Tap-to-Pay sale, resolved from the Stripe payment intent id. TERM-IDEMP-01: requires a caller-scoped Idempotency-Key; a replayed key returns the cached terminal response instead of re-sending.
POST/api/v1/admin/notifications/broadcastBearer or API key
Send broadcast
Send one or more push, email, and SMS channels to all members, selected member ids, or a server-resolved tag/pass/class audience. Idempotency-Key is required. Each channel derives a stable per-recipient delivery reference; a partial retry skips terminal successes/suppressions and resumes failed legs. Returns sent/skipped/failed counts per channel.
Parameters, scopes and examples
Required scopes
write:notifications
Broadcast
Request body
{
"channels": [
"email",
"sms"
],
"title": "New class added",
"target": {
"type": "tag",
"tag": "vip"
},
"subject": "New class added",
"body": "Check out our new Hot Power class on Saturday!"
}
GET/api/v1/admin/notifications/recentBearer or API key
Recent notifications
Recent email, SMS, and push notifications sent by the venue.
Parameters, scopes and examples
Required scopes
read:notifications
POST/api/v1/admin/staff/inviteBearer token
Invite a staff member
PROMPT_02 (S1-03) — provisions the auth user + profile + membership (status=invited), mints a staff_invitations claim token, and emails the venue-branded /auth/claim-invite link. Permission: staff.manage. The token is consumed by the WEB claim page (set password → membership flips invited→active); there is no separate accept API endpoint because the claim sets a password. 409 EMAIL_EXISTS when a Booking Bible account already exists for the email (adding an existing user as staff is a role change — use the admin UI). location_ids is stored on the invitation for record-keeping; location assignment remains a post-onboarding admin action. Emits staff.invited. Idempotency-Key supported.
Every staff shift in the venue for a date range. Permission: staff_scheduling.view. Joins staff profile name. Optional ?status= filter.
Parameters, scopes and examples
Query parameters
fromstring
Start ISO datetimeDefault: -7 days
tostring
End ISO datetimeDefault: +14 days
statusstring
Filter by ShiftStatus
POST/api/v1/admin/staff-scheduleBearer token
Create a staff shift
Create a new shift. Permission: staff_scheduling.manage. Note: API path skips the engine compliance pre-checks; for full compliance use the admin panel or the createShift server action.
POST/api/v1/admin/walk-in-queue/{id}/callBearer or API key
Call queue entry
Mark a queue entry as called and notify the client by SMS if they opted in. Permission: bookings.manage.
Parameters, scopes and examples
Required scopes
write:bookings
Path parameters
idstring · required
Queue entry ID
DELETE/api/v1/admin/walk-in-queue/{id}Bearer or API key
Remove walk-in
Cancel/remove a walk-in queue entry. Permission: bookings.manage.
Parameters, scopes and examples
Required scopes
write:bookings
Path parameters
idstring · required
Queue entry ID
GET/api/v1/admin/checkin/{classInstanceId}/qr-tokenBearer or API key
Get check-in QR token
Returns the current rotating QR token for a class instance. A new token is generated if none exists or the existing one is expired. Force rotation with ?refresh=true. Token TTL: 5 minutes. Permission: booking.checkin.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
GET/api/v1/admin/rates/distributionBearer or API key
Get revenue distribution by rate
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
Accepts exactly one credential: Bearer JWT with `rates.view`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication. The client and pass type must both belong to that venue.
Accepts exactly one credential: Bearer JWT with `rates.override`, or an API key bound to the venue with `write:passes`. Dual credentials are rejected before authentication.
DELETE/api/v1/admin/rates/override/{passId}Bearer or API key
Clear a pass rate override
Accepts exactly one credential: Bearer JWT with `rates.override`, or an API key bound to the venue with `write:passes`. Dual credentials are rejected before authentication.
Parameters, scopes and examples
Required scopes
write:passes
Path parameters
passIdstring · required
Pass id
Response example
{
"data": {
"ok": true
},
"error": null
}
GET/api/v1/admin/private-eventsBearer or API key
List private-event bookings
Accepts exactly one credential: Bearer JWT with `private_events.view`, or an API key bound to the venue with `read:private_events`. Targets are non-enumerating and venue-scoped.
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
Parameters, scopes and examples
Required scopes
write:private_events
Private-event booking. Every PS-B2 field below is OPTIONAL and additive: client_id / save_as_client (link or create the client the session is for), partner_id + billing_target/billing_address/billing_vat_number/po_number/department/cost_center (bill a company — the billing block prefills from the partner record), brand_id, location_id, staff_note (a message the client sees), pricing_override ({mode: per_person|total, amount} — total is VAT-inclusive), and start_mode (confirmed | inquiry | confirm_on_payment) with payment_due_at. The legacy `status` field keeps working.
GET/api/v1/admin/private-events/{id}Bearer or API key
Get a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.view`, or an API key bound to the venue with `read:private_events`. Targets are non-enumerating and venue-scoped.
PATCH/api/v1/admin/private-events/{id}Bearer or API key
Update a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
Parameters, scopes and examples
Required scopes
write:private_events
Path parameters
idstring · required
Booking id
Fields to update. PS-B2 adds the same optional fields the create route takes (client_id, partner_id + billing block, brand_id, location_id, staff_note, pricing_override, payment_due_at) plus `reprice` (recompute the frozen subtotal/VAT/total/deposit) and `notify_client` ({enabled, channels}). The response carries the client-visible change summary.
POST/api/v1/admin/private-events/{id}/approveBearer or API key
Approve a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
POST/api/v1/admin/private-events/{id}/cancelBearer or API key
Cancel a private-event booking
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
POST/api/v1/admin/private-events/{id}/quoteBearer or API key
Send a private-event quote
Accepts exactly one credential: Bearer JWT with `private_events.manage`, or an API key bound to the venue with `write:private_events`. The canonical venue-scoped mutation workflow is used.
Accepts exactly one credential: Bearer JWT with `loyalty_price.manage`, or an API key bound to the venue with `read:passes`. Dual credentials are rejected before authentication.
POST/api/v1/admin/loyalty-price/grantBearer or API key
Give a client the loyalty price
Accepts exactly one credential: Bearer JWT with `loyalty_price.grant`, or an API key bound to the venue with `write:passes`. Writes through the context-free grant core (never a cookie action), so the audit trail and status recompute are identical to the admin web surface.
Parameters, scopes and examples
Required scopes
write:passes
user_id + a short reason. Optional venue-local expiry, and an optional pass_id with an agreed price on the catalog (MAJOR) scale — pass_price_override requires pass_id.
Request body
{
"user_id": "uuid",
"reason": "Agreed with the owner at the desk",
"expires_on": "2027-01-31",
"pass_id": "uuid",
"pass_price_override": 249
}
List every event on the unified calendar (classes, appointments, private events, streams, blocked time, instructor unavailability, blackouts, room rentals, maintenance, staff shifts, open gym) in a date range. JWT (any staff role) returns the org feed; API key with read:calendar returns the same. Filters: room_id, staff_id, location_id, brand_id, sources (comma-separated), only_blocking.
List maintenance slots in a date range. API key with read:maintenance scope. Filters: start, end (ISO datetime), room_id, status, limit (1-200, default 50).
Create a maintenance slot. API key with write:maintenance. Body: maintenance_type (preventive | corrective | inspection | deep_clean | equipment | renovation), title, start_time, end_time, plus optional priority, room_id, equipment_id, blocks_room (default true), assigned_staff_id, vendor_name, vendor_contact, estimated_cost, notes. Idempotency-Key header honored. When blocks_room is true and a room is set, conflicts against classes / appointments / private events / streams / room rentals / other maintenance return 409 with the conflict list. Emits maintenance.scheduled.
Parameters, scopes and examples
Required scopes
write:maintenance
Maintenance creation payload
Request body
{
"maintenance_type": "deep_clean",
"title": "Quarterly studio deep clean",
"start_time": "2026-05-01T20:00:00Z",
"end_time": "2026-05-01T22:00:00Z",
"room_id": "uuid",
"priority": "normal",
"blocks_room": true
}
Staff33 documented operations
GET/api/v1/staff/scheduleBearer token
My teaching schedule
Instructor's classes. Optional scope=own|partner|all; every row includes origin venue metadata and origin.timezone so apps bucket collaboration classes in the owning venue's local day.
GET/api/v1/staff/earningsBearer token
My earnings
Compensation, tips, and commissions broken down by period and class. tips_settled_via_collaboration is additive visibility for gratuities paid on a practitioner statement and is deliberately excluded from tips_received and total.
GET/api/v1/staff/classes/{id}/rosterBearer token
Class roster
View attendee list for a class the instructor is assigned to. Returns class and booking updated_at CAS tokens, venue-local day_state, and historical_capabilities. include_historical_records=true additionally exposes terminal roster rows and requires scheduling.manage_history.
Business-app staff correction using the same atomic ledger as Admin. Requires an active venue, roster access, class assignment where applicable, scheduling.manage_history, and the ordinary operation permission. Every operation requires expected_class_updated_at; existing rows also require expected_updated_at. Delivery is default-silent.
Parameters, scopes and examples
Path parameters
idstring · required
Class instance ID
bookingIdstring · required
Class booking ID
Bounded historical roster correction with UUID Idempotency-Key
Provider-scoped atomic correction for an isolated past class. The active provider must be assigned to the existing class; retrocreate must assign that provider directly, and assignment corrections must retain them. Requires schedule.view_own, scheduling.manage_history, scheduling.manage, UUID Idempotency-Key, CAS evidence for existing rows, past effective_at, and typed REWRITE. Notifications are always silent.
Mark or unmark a participant present for a course session ({user_id, present}). Idempotent; writes the same attendance store the web roster uses. Supports Idempotency-Key.
Send an email or SMS to course participants (audiences: enrolled, waitlisted, all, by track, by payment status, hand-picked). Requires course-manage scope; rate-limited; supports Idempotency-Key (retries never double-send).
Parameters, scopes and examples
Path parameters
idstring · required
Course ID
Message
Request body
{
"channel": "email",
"subject": "Bring a mat tomorrow",
"message": "Hi everyone — please bring your own mat to tomorrow’s session.",
"audience": {
"kind": "enrolled"
}
}
GET/api/v1/staff/availabilityBearer token
List my unavailable dates
Calling staff member's current and future unavailable dates for the selected venue. Permission: staff_portal.availability.
POST/api/v1/staff/availabilityBearer token
Set availability
Add or update unavailable dates for the calling staff member. Permission: staff_portal.availability.
Strict partial update of a current/future window using the exact updated_at token returned by GET. Caller must own the window; another instructor requires staff.edit. A stale token returns 409 STALE_TARGET. Existing or target ranges touching venue-local history fail closed until the dedicated executor is installed.
Parameters, scopes and examples
Path parameters
idstring · required
Window ID
Concurrency token plus one or more changed window fields
Sets is_active=false on a current/future window using the exact updated_at token returned by GET, after tenant and owner-or-staff.edit authorization. A stale token returns 409 STALE_TARGET. Historical ranges fail closed until the dedicated executor is installed.
Atomic, immutable-ledger correction for a past recurring availability window owned by the active staff member. Requires availability.manage_history, staff_portal.availability, UUID Idempotency-Key, expected_updated_at plus expected_is_active for existing rows, a past effective_at, and typed REWRITE. Notifications are always silent.
Parameters, scopes and examples
Path parameters
idstring · required
Availability window ID
Self-owned historical availability correction
Request body
{
"operation": "availability_window.invalidate",
"expected_updated_at": "2026-08-20T09:00:00.000Z",
"expected_is_active": true,
"history_reason": "Approved rota confirms that this window did not apply",
"history_confirmation_token": "REWRITE",
"effective_at": "2026-08-10T10:00:00.000Z",
"intent": {}
}
GET/api/v1/staff/substitute-poolBearer token
Read substitute-pool opt-in
Returns { enabled, updated_at } for the calling user's active org.
PUT/api/v1/staff/substitute-poolBearer token
Toggle substitute-pool opt-in
Set whether the calling user is available to be auto-suggested as a substitute. Body: { enabled: boolean }. Emits substitute_pool.opt_in_changed.
Parameters, scopes and examples
Opt-in state
Request body
{
"enabled": true
}
GET/api/v1/staff/appointmentsBearer token
My appointments
Cursor-paginated list of the calling provider's appointments, including venue currency and the same client name and 80-character provider-note preview shown in the web staff list. Contact details are not exposed. Query params: cursor (opaque next_cursor; legacy ISO timestamps are temporarily accepted), limit (1..100, default 25), status (one of the appointment status strings), direction (upcoming|past, default upcoming).
Parameters, scopes and examples
Query parameters
cursorstring
Opaque next_cursor returned by the previous page
limitnumber
Page size (1..100)Default: 25
statusstring
Optional status filter
directionstring
upcoming | pastDefault: upcoming
GET/api/v1/staff/appointments/{id}Bearer token
My assigned appointment detail
Provider-scoped detail with updated_at CAS evidence, server-authoritative historical review flags, privacy-gated client contact fields, and exact per-channel notification availability. The route always binds provider_id to the caller.
PATCH/api/v1/staff/appointments/{id}Bearer token
Act on my assigned appointment
Provider-scoped check_in, start, complete, no_show, cancel, or reschedule. Requires the action-specific appointments.*_own permission, exact expected_updated_at, and Idempotency-Key. Client notifications are default-silent and require explicit notification_channels plus notifications.send and server preflight. Past/terminal mutations fail closed until the appointment historical executor is installed.
Parameters, scopes and examples
Exact provider lifecycle intent and caller-rendered concurrency snapshot
Provider-scoped form of the dedicated atomic appointment-history command. Requires staff_portal.appointments, appointments.manage_history, the ordinary operation permission, a UUID Idempotency-Key, REWRITE attestation, and exact expected_updated_at plus expected_status CAS for existing rows. The existing appointment and any retrocreate or assignment target must remain assigned to the active provider. Corrections are always silent. Returns 503 HISTORICAL_EXECUTOR_UNAVAILABLE without table-call fallback until correct_appointment_historical is installed.
Parameters, scopes and examples
Required scopes
appointments.manage_history
Path parameters
idstring · required
Appointment UUID
The same closed appointment correction body as the admin route
Calling staff member's own non-instructor shifts (reception, cleaning, manager, front desk) in a date range. Use ?from=&to= ISO datetimes; defaults to next 14 days.
Parameters, scopes and examples
Query parameters
fromstring
Start ISO datetimeDefault: now
tostring
End ISO datetimeDefault: +14 days
POST/api/v1/staff/shifts/clock-inBearer token
Clock in
Clock in to an own staff shift. Allowed from 15 min before scheduled start through 30 min after. Sets status to in_progress and stamps clock_in_at. Emits shift.clock_in.
Parameters, scopes and examples
Shift to clock in to
Request body
{
"shift_id": "uuid"
}
POST/api/v1/staff/shiftsAPI key
Create a staff shift
Create a non-instructor staff shift. API-key only (write:staff). Body: start_time, end_time, optional staff_id, shift_type (regular | overtime | on_call | training | meeting), break_minutes, role_required, location_id, hourly_rate, notes. Idempotency-Key header honored. Emits shift.created (and shift.assigned if a staff_id is set).
Soft-cancel a shift (sets status=cancelled, preserves audit/payroll references). JWT (admin/manager) or API key with write:staff. Use ?reason= to attach a cancellation reason to the audit row.
Parameters, scopes and examples
Required scopes
write:staff
Path parameters
idstring · required
Shift UUID
Query parameters
reasonstring
Cancellation reason (free text)
POST/api/v1/staff/clockBearer token
Clock in or out (unified)
Unified clock-in/out endpoint. JWT only — resolves the staff member from the session token. Body: { action: "in" | "out", shift_id }. On clock-out the response includes actual_hours and total_pay. Emits shift.clock_in or shift.clock_out.
Parameters, scopes and examples
Clock action
Request body
{
"action": "in",
"shift_id": "uuid"
}
POST/api/v1/staff/shifts/clock-outBearer token
Clock out
Clock out of an in-progress staff shift. Computes actual_hours, actual_break_minutes, and total_pay (when hourly_rate is set). Returns warnings for break/EU compliance issues. Emits shift.clock_out.
Parameters, scopes and examples
Shift to clock out of
Request body
{
"shift_id": "uuid"
}
GET/api/v1/staff/time-offBearer token
My time-off requests
Latest 100 own time-off requests across all statuses.
POST/api/v1/staff/time-offBearer token
Request time off
Submit a new time-off request. Always created with status=pending. Manager approval/decline happens via the admin panel. Emits time_off.requested.
Create or update a lead for the venue. Public rate-limited (10 req/min/IP) or API-key authenticated (write:leads). Upserts on (organization_id, email): provided fields populate blanks, existing non-null values are preserved. Fires the lead_captured analytics event and emits a lead.created webhook with the full record plus an attribution object (utm_*, fbclid, gclid, landing_page, referrer).
Parameters, scopes and examples
Required scopes
write:leads
Lead payload. Org resolves from API key > X-Organization-ID header > subdomain > organization_id.
List leads for the API key's organization. API key only (JWT not permitted). Requires the read:leads scope.
Parameters, scopes and examples
Required scopes
read:leads
Query parameters
searchstring
Search by email, first_name, or last_name
sourcestring
Filter by source (website_form, exit_intent, referral, etc.)
statusstring
Filter by status (new, contacted, converted, unsubscribed)
pageinteger
Page numberDefault: 1
limitinteger
Items per page (max 100)Default: 20
Events3 documented operations
POST/api/v1/eventsPublic
Track an analytics event
Record a server-side analytics event into user_events. Public rate-limited (60 req/min/IP) or API-key authenticated (write:events). For conversion event names (purchase, subscribe, refund, lead_captured) we additionally fire Meta CAPI + GA4 MP when the venue has pixel credentials configured.
Parameters, scopes and examples
Required scopes
write:events
Event payload. UTM + click-id + page URL get merged into event_properties.
Create an open-gym session for a client. Validates an active pass with allow_open_gym=true and the access schedule. JWT users self-check in; API keys must include user_id.
Parameters, scopes and examples
Required scopes
write:bookings
Optional location, source, pass override, and notes.
Returns the latest version of each active required waiver for the authenticated client in the validated X-Organization-ID venue, including the exact markdown body to display and the latest version the client signed. `body_md` is canonical; `body` is the native-app compatibility alias with the same value.
Removes the caller's own club membership. Idempotency-Key supported; leaving a club you are not in is a no-op success. Emits club.member_left (audit + webhook).
Parameters, scopes and examples
Path parameters
idstring · required
Club id
Response example
{
"data": {
"ok": true
},
"error": null
}
DELETE/api/v1/clubs/{id}/membershipBearer or API key
Leave a club (membership alias)
REST-shaped alias for POST /clubs/{id}/leave used by the mobile clubs contract — identical behavior (Idempotency-Key, no-op success when not a member, club.member_left emit).
Parameters, scopes and examples
Path parameters
idstring · required
Club id
Response example
{
"data": {
"ok": true
},
"error": null
}
GET/api/v1/clubs/suggestionsBearer or API key
List club suggestions (admin)
Admin queue of client-submitted club suggestions. Filter by status.
Returns a single chat channel summary (channel row + unread_count + last_message_at) for the authenticated org. Staff role (or chat.read scope) required.
Bulk Scan Session — map a single scanned barcode to a preset target
Hot-path endpoint for the rapid-mapping Bulk Scan Session. Each call maps one scanned barcode. Returns status=created (new mapping), duplicate_in_session (same barcode+target already exists), requires_confirmation (different target, resend with allow_overwrite=true to proceed), or overwritten.
Model Context Protocol server (HTTP transport, JSON-RPC 2.0, protocol 2025-03-26). Authenticate with `X-API-Key`. Methods: `initialize`, `ping`, `resources/list`, `resources/read`, `tools/list`, `tools/call`. Read-only in v1. See `/developers/mcp` for the full guide.
Returns every registered feature module with its resolved enabled/settings/source for the calling venue. Resolution honors the four-tier precedence (tenant override → group lock → venue → group default → plan → default). Mobile Business app uses this for parity with /admin/settings/features.
Parameters, scopes and examples
Response example
{
"data": [
{
"key": "leaderboards",
"label": "Leaderboards",
"description": "Member-facing leaderboards by class type, period, and metric.",
"category": "Community",
"enabled": true,
"source": "plan",
"locked_by_group": false,
"settings": {}
}
]
}
PATCH/api/v1/admin/features/[moduleKey]Bearer or API key
Update a venue-level feature toggle
Flip enabled/settings for a feature module at the venue tier. Idempotency-Key supported. Returns 400 with `Locked by group: <paths>` when the venue tries to flip a group-locked toggle or write to a group-locked dot-path in `settings`. Audit-logged + emits `feature_toggle.changed` webhook.
Parameters, scopes and examples
Required scopes
write:settings
Path parameters
moduleKeystring · required
Module key from feature_modules.key
Partial update — only the fields you want to change.
Browse partner venues available to the member across the BOOKING BIBLE network. Each entry exposes a public summary plus the exact relationship status, active partnership id, and venue-level bookable flag for the organization selected by X-Organization-ID. Member-JWT.
Book a class at a partner venue using a network-eligible pass. Resolves the legal gate against the HOST venue’s documents before booking. Requires a caller-stable `Idempotency-Key` header; exact retries return the original booking and visit. Member-JWT.
Creates a venue-to-venue Network partnership request through the context-free Network mutation core. Bearer JWT requires network.manage; API keys require write:network.
GET/api/v1/network/partnerships/{id}Bearer or API key
Read a venue Network partnership
Reads one venue-to-venue Network partnership after proving the caller belongs to either party. Bearer JWT requires network.view; API keys require read:network.
PATCH/api/v1/network/partnerships/{id}Bearer or API key
Update a venue Network partnership
Updates a venue-to-venue Network partnership through the commercial lifecycle. Bearer JWT requires network.manage. API keys with write:network may change lifecycle status, but agreement negotiation and terms revisions require a verified human JWT administrator and return 403 for API-key callers.
DELETE/api/v1/network/partnerships/{id}Bearer or API key
Terminate a venue Network partnership
Terminates immediately only when binding and notice have both elapsed; otherwise schedules termination through the locked service RPC. Bearer JWT requires network.manage; API keys require write:network.
GET/api/v1/network/partnerships/{id}/visitsBearer or API key
List visits for a venue Network partnership
Lists visit ledger rows for one venue-to-venue Network partnership after proving the caller belongs to either party. Bearer JWT requires network.view; API keys require read:network.
GET/api/v1/network/partnerships/{id}/settlementsBearer or API key
List settlements for a venue Network partnership
Lists network-only settlements for one venue-to-venue Network partnership after proving the caller belongs to either party. Bearer JWT requires network.view; API keys require read:network.
Lists collaborations for the workspace selected by X-Organization-ID. Returns venue-owned relationships and invitations received by an owned professional workspace. Supplying the exact email query performs the privacy-preserving invitation lookup and requires network.manage.
Creates a pending venue-to-professional collaboration with an explicit venue role and compensation model. Requires network.manage and a non-individual venue workspace.
Accepts or declines an invitation from the professional workspace, or lets the venue set role, pause, resume, or terminate the relationship. Every operation is tenant-checked and requires network.manage.
Ends the relationship through the canonical termination core and suspends its venue membership unless keep_membership is explicitly true. Either party may terminate; requires network.manage.
Parameters, scopes and examples
Optional termination reason and membership handling
List the caller’s relationships (bidirectional — both relationships the member created and ones pointing back at them), hydrated with the linked member’s profile. Unlocks family pricing, shared booking, and pass sharing. Member-JWT, org-scoped.
Add a relationship. When `related_email` matches a member in the same venue, the relationship links to their profile and a mirror row is written so both members see it. Member-JWT. Idempotency-Key supported.
Submit a private-event inquiry as the authenticated member. Validates participant count against the event type’s min/max, computes pricing, and inserts a `private_event_bookings` row with `booked_by` set; emits `private_event.inquiry_created`. Member-JWT, org from X-Organization-ID. Idempotency-Key supported.
PROMPT_11 — returns the Stripe `client_secret`, frozen `merchant_country_code`, and `stripe_account_id` (`acct_*` for a direct Connect PI, otherwise null) for the booking’s deposit/full charge so the member can initialize Stripe Elements in the exact payment context. Customer/ephemeral-key credentials are returned only when this member owns the customer frozen by the first payment operation; admin-created or another accepted booker identity receives a safe generic sheet with null customer credentials. Idempotent (reuses the frozen PaymentIntent execution created at confirmation). `{ skipped: true }` when the event type’s payment_mode is `none`. Member-JWT; ownership by contact_email.
Member approves a quoted booking and gets Payment Sheet credentials
The member’s “Approve & pay” CTA: the booker confirms a quote the venue sent (status `quoted`) and receives the same frozen PaymentIntent, `merchant_country_code`, and `stripe_account_id` (`acct_*` only for direct Connect; otherwise null). Customer/ephemeral-key credentials are returned only to the user id that owns the frozen Stripe customer; another accepted booking identity receives a generic sheet with null customer credentials. Member-JWT; ownership by `booked_by` or `contact_email`. Idempotency-Key header REQUIRED — a retry re-enters the repairable confirmation pipeline and returns the same frozen execution (no duplicate PI, account drift, or regional drift). Honors the event type’s payment_mode via the shared helper; `{ skipped: true }` when payment_mode is `none` (invoice path).
PROMPT_11 — public catalog of a venue’s active, publicly-listed private-session types for the embeddable widget (/embed/private-sessions). Cross-origin access is governed by the platform dynamic CORS allowlist (venue custom domains). Cached, IP-throttled.
List products for the authenticated venue. Business-app JWTs require pos.access; API keys require read:products. Archived products are hidden unless include_archived=true.
Parameters, scopes and examples
Required scopes
read:products
Query parameters
include_archivedboolean
Include archived products. Defaults to false.Default: false
POST/api/v1/admin/productsAPI key
Create a venue product
Create through the canonical product mutation contract. Unknown/protected fields are rejected; initial stock creates one movement.
Parameters, scopes and examples
Required scopes
write:products
GET/api/v1/admin/products/{id}Bearer or API key
Get a venue product
Get one product only when it belongs to the authenticated venue. Business-app JWTs require pos.access; API keys require read:products.
Parameters, scopes and examples
Required scopes
read:products
Path parameters
idstring · required
Product UUID
PATCH/api/v1/admin/products/{id}Bearer or API key
Update a venue product
Update mutable catalog fields through the canonical product core. Business-app JWTs require products.manage; API keys require write:products. Products and its tier-gated Point of Sale dependency must be active. stock_quantity and protected fields are rejected.
Parameters, scopes and examples
Required scopes
write:products
Path parameters
idstring · required
Product UUID
DELETE/api/v1/admin/products/{id}API key
Archive a venue product
Archive through canonical catalog semantics (is_active=false plus archived_at). Permanent deletion is separate and guarded.
Parameters, scopes and examples
Required scopes
write:products
Path parameters
idstring · required
Product UUID
GET/api/v1/venues/{slug}/product-packagesPublic
List buyable clip cards
Public catalog of active product passes (clip cards) for a venue. Cached, IP-throttled.
Initiate a product-pass (clip card) purchase. A nonempty Idempotency-Key header is required and defines the durable operation. Returns Customer/ephemeral-key credentials in the same frozen Stripe account as the PaymentIntent, plus `merchant_country_code` and `stripe_account_id` (`acct_*` only for direct Connect; otherwise null). A service-only pre-provider claim binds tenant, catalog, customer, regional, routing, fee, amount, and currency; `product_passes` is granted atomically on `payment_intent.succeeded`. Gated on the `products` module + venue legal docs. Member-JWT.
Buy N paid tickets for a community event (`{id}` is the event booking id). Price = `member_price` + `guest_price` × (ticket_count − 1). Requires an Idempotency-Key header. Returns Customer/ephemeral-key credentials in the same frozen Stripe account as the PaymentIntent, plus `merchant_country_code` and `stripe_account_id` (`acct_*` only for direct Connect; otherwise null). On `payment_intent.succeeded` the ticket order flips to paid and a `going` RSVP is upserted with `guest_count = ticket_count − 1`. Gated on the `community_events` module. Member-JWT.
Strictly necessary cookies keep the site working. With your consent we use analytics and marketing cookies to improve the experience and measure ad performance. You can change this any time from your account’s privacy settings.