{"openapi":"3.1.0","info":{"title":"PlaceFull API","version":"2.0.0","description":"# PlaceFull API\n\nPlaceFull is a booking platform for studios and service businesses. Use the REST API to manage catalog, availability, bookings, payments, memberships, and customer records — or embed the public **storefront** surface for self-serve booking.\n\nAll successful responses use a `{ \"data\": … }` envelope. Money amounts are **integer minor units** (cents). Timestamps are **ISO-8601** strings in UTC.\n\n## Base URLs\n\n| Environment | URL |\n| --- | --- |\n| **Production** | `https://placefull.ai` |\n| **Local** | `http://localhost:3000` |\n\nUse the **Production** or **Local** server selector above when trying requests in this reference.\n\n## Authentication\n\nPlaceFull accepts two credential types:\n\n1. **Session bearer** — passwordless login for operators and customers.\n2. **API key** — machine access for integrations and MCP (`bk_…` prefix).\n\n### Passwordless session\n\n**Step 1 — request a verification code**\n\n```bash\ncurl -sS -X POST https://placefull.ai/auth/challenges \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"you@example.com\",\"channel\":\"email_code\"}'\n```\n\nResponse `data.challengeId` identifies the challenge. The code is delivered by email (or SMS when enabled).\n\n**Step 2 — verify and receive a session token**\n\n```bash\ncurl -sS -X POST https://placefull.ai/auth/verify \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"challengeId\":\"<challenge-id>\",\"code\":\"123456\"}'\n```\n\n**Step 3 — send the token on authenticated requests**\n\n```bash\ncurl -sS https://placefull.ai/me/profile \\\n  -H 'Authorization: Bearer <sessionToken>'\n```\n\nSession tokens expire. Repeat the flow when you receive `401 unauthorized`.\n\n### API key\n\nCreate a key with `POST /businesses/{businessId}/api-keys` (session auth, `business.manage`). The plaintext `bk_` key is returned once. Send it as a Bearer token on feature-gated `/businesses/*` routes:\n\n```bash\ncurl -sS https://placefull.ai/businesses/<business-id>/customers \\\n  -H 'Authorization: Bearer bk_your_api_key_here'\n```\n\nThat example needs feature `crm.view`. API keys are not accepted on `/me/*`, `POST /businesses`, or the api-keys routes themselves — a key cannot mint its own successor. Gated operator routes also require the **feature** named in each operation's description (for example `booking.manage`).\n\n### Agents\n\nPoint an agent host at this base URL.\n\n| What | URL |\n| --- | --- |\n| **MCP (Streamable HTTP)** | `POST https://placefull.ai/mcp` |\n| **Server card** | `https://placefull.ai/.well-known/mcp.json` |\n| **Agent guide** | `https://placefull.ai/llms.txt` |\n| **OAuth metadata** | `https://placefull.ai/.well-known/oauth-authorization-server` |\n| **Operator setup (console)** | `https://placefull.ai/app/settings?show=integrations` |\n\n**Claude (recommended):** paste `https://placefull.ai/mcp` into Settings → Connectors → Add custom connector → Connect → sign in with the operator email. OAuth 2.1 + PKCE — no API key.\n\n**Cursor / CI:** create a `bk_` API key and send `Authorization: Bearer bk_…` on `POST /mcp`.\n\nUnauthenticated `POST /mcp` returns `401` with `WWW-Authenticate` pointing at protected-resource metadata so clients discover OAuth automatically.\n\n## API surfaces\n\n| Surface | Prefix | Audience |\n| --- | --- | --- |\n| **Operator API** | `/businesses/…`, `/offerings/…`, `/locations/…`, … | Operators and integrations managing a business |\n| **Storefront API** | `/storefront/…` | Public embeddable booking widgets |\n| **Customer self-service** | `/me/…` | Signed-in customers managing their profile and bookings |\n\nStorefront routes are **public read** (no auth) except booking hold and confirm, which require a customer session. Storefront routes are **rate limited** — see below.\n\n## Errors\n\nErrors return a **non-2xx** status with this envelope:\n\n```json\n{\n  \"error\": {\n    \"code\": \"validation\",\n    \"message\": \"email is required\",\n    \"details\": {}\n  }\n}\n```\n\n| Code | HTTP | Meaning |\n| --- | --- | --- |\n| `validation` | 400 | Invalid input |\n| `unauthorized` | 401 | Missing or invalid credentials |\n| `forbidden` | 403 | Authenticated but not permitted (missing feature or role) |\n| `not_found` | 404 | Resource does not exist |\n| `conflict` | 409 | State conflict (capacity, duplicate, or concurrent hold lost) |\n| `too_many_requests` | 429 | Rate limit exceeded |\n| `internal_error` | 500 | Unexpected server error |\n\n## Rate limits\n\n**Storefront** routes (`/storefront/…`) are limited to **480 requests per minute per visitor** by default (`STOREFRONT_RATE_LIMIT_MAX` / `STOREFRONT_RATE_LIMIT_WINDOW_MS`). The visitor is the `cf-connecting-ip` header when it is a single IP, otherwise the connection address. Cart and other unauthenticated storefront writes have a separate limit of **60 per minute** (`STOREFRONT_WRITE_RATE_LIMIT_MAX`). When exceeded, the API returns **429** `too_many_requests` with a `Retry-After` header (seconds until the window resets). Operator routes are not globally rate limited in v1.\n\n## Pagination\n\n**Offset pagination** — CRM customer list (`GET /businesses/:id/customers`):\n\n- Query: `limit` (default 50), `offset` (default 0)\n- Response `data`: `{ customers, total, limit, offset }`\n\n**Cursor pagination** — storefront offering lists (`GET /storefront/locations/:id/offerings`), the Products list (`GET /businesses/:id/products`), and one option's stock ledger (`GET /products/:productId/variants/:variantId/stock`):\n\n- Query: `limit`, `cursor` (opaque; omit on first page)\n- Response `data`: `{ items, nextCursor }` — pass `nextCursor` as `cursor` for the next page; `null` means end.\n\n## Versioning\n\n`info.version` tracks the REST contract. **Breaking** changes (removed fields, renamed paths, semantic changes) bump the major version. Additive changes (new optional fields, new endpoints) are minor. The MCP surface is versioned separately via tool schemas.\n\nDownload this spec from [`/openapi.json`](https://placefull.ai/openapi.json) to generate clients or import into Postman.","contact":{"name":"PlaceFull Developer Support","email":"developers@bookable.app","url":"https://placefull.ai"},"license":{"name":"Proprietary","url":"https://placefull.ai/terms"},"x-logo":{"url":"https://placefull.ai/branding/lockup.png","altText":"PlaceFull","href":"https://placefull.ai"}},"servers":[{"url":"https://placefull.ai","description":"Production"},{"url":"http://localhost:3000","description":"Local"}],"tags":[{"name":"system","description":"Process health and platform status"},{"name":"auth","description":"Passwordless authentication"},{"name":"person","description":"Person identities"},{"name":"business","description":"Business profiles and settings"},{"name":"location","description":"Physical locations"},{"name":"catalog","description":"Spaces, team, and offerings"},{"name":"products","description":"Products, their options, and the stock ledger"},{"name":"availability","description":"Schedule projection and bookable slots"},{"name":"booking","description":"Operator booking lifecycle"},{"name":"commerce","description":"Payments, balances, and Stripe Connect"},{"name":"crm","description":"Customer records and export"},{"name":"customers","description":"Customer lists and the messages sent to them"},{"name":"membership","description":"Plans, benefits, and pricing"},{"name":"access","description":"Team roles and feature gates"},{"name":"waitlist","description":"Waitlists for full dates"},{"name":"chat","description":"Operator chat — an LLM agent over the intent tools"},{"name":"me","description":"Customer self-service for the signed-in person"},{"name":"storefront","description":"Public embeddable booking surface"}],"x-tagGroups":[{"name":"Platform","tags":["system","auth","person","access"]},{"name":"Operator API","tags":["business","location","catalog","products","availability","booking","commerce","crm","customers","membership","waitlist","chat"]},{"name":"Storefront API","tags":["storefront","me"]}],"paths":{"/businesses/{businessId}/accounting/connect":{"get":{"operationId":"startAccountingConnect","summary":"Start a QuickBooks Online connection","description":"Records a one-shot attempt for the caller and returns the Intuit authorize URL. The console sends the operator there; Intuit returns to `GET /accounting/callback`, which files the answer against the attempt and redirects to Settings → Accounting with `accounting=finish` and the attempt id. The console then calls `POST …/accounting/connect/complete`. Tokens never appear on this response. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"authorizeUrl":{"type":"string"}},"required":["authorizeUrl"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/accounting/connect/complete":{"post":{"operationId":"finishAccountingConnect","summary":"Finish a QuickBooks Online connection","description":"The attempt id from the `?attempt=` Settings landed with after Intuit. The signed-in person must be the one who started the connect, the attempt is used once and only within fifteen minutes, and only then is Intuit’s code exchanged and the encrypted connection written (security audit M2). `outcome` is `connected`, or `error` for anything else. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"attemptId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["attemptId"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"outcome":{"type":"string","enum":["connected","error"]}},"required":["outcome"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/accounting/connection":{"get":{"operationId":"getAccountingConnection","summary":"Get the live accounting connection","description":"Company name, home currency, start date and status. Never tokens. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"connection":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"provider":{"type":"string","const":"quickbooks_online"},"companyName":{"type":"string"},"homeCurrency":{"type":"string"},"externalCompanyId":{"type":"string"},"status":{"type":"string","enum":["connected","needs_reauth","disconnected"]},"startDate":{"type":"string"},"startDateFrozen":{"type":"boolean"},"lastSyncAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"connectedAt":{"type":"string"}},"required":["id","provider","companyName","homeCurrency","externalCompanyId","status","startDate","startDateFrozen","lastSyncAt","lastError","connectedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["connection"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateAccountingConnection","summary":"Update the posting start date","description":"Editable until the first post, then frozen (MDH-159). Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"startDate":{"type":"string"}},"required":["startDate"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"connection":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"provider":{"type":"string","const":"quickbooks_online"},"companyName":{"type":"string"},"homeCurrency":{"type":"string"},"externalCompanyId":{"type":"string"},"status":{"type":"string","enum":["connected","needs_reauth","disconnected"]},"startDate":{"type":"string"},"startDateFrozen":{"type":"boolean"},"lastSyncAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"connectedAt":{"type":"string"}},"required":["id","provider","companyName","homeCurrency","externalCompanyId","status","startDate","startDateFrozen","lastSyncAt","lastError","connectedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["connection"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"disconnectAccountingConnection","summary":"Disconnect QuickBooks Online","description":"Revokes at Intuit and stamps disconnected_at. Posted batches keep their external ids. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"204":{"description":"No content"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/accounting/map":{"get":{"operationId":"getAccountingMap","summary":"Propose the QuickBooks account map","description":"One row per required category and tax rate, with a ranked proposal from the chart. Save confirms selections; Create writes a new account through the provider. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"map":{"type":"object","properties":{"complete":{"type":"boolean"},"missingCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"}},"required":["id","name","type"],"additionalProperties":false}},"rows":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","enum":["income.class","income.session","income.space","income.membership","income.pack","income.product","income.other","income.revenue_category","income.booking_fee","income.uncategorized","liability.sales_tax","expense.stripe_fees","expense.booking_fees","expense.disputes","expense.dispute_fees","expense.stripe_other","clearing.stripe","clearing.trx","expense.trx_fees","asset.cash_on_hand","asset.bank"]},"taxRateId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"revenueCategoryId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Set on income.revenue_category rows — one account per revenue category, as sales tax is one per rate (architecture/31)."},"revenueCategoryName":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxRateName":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxRatePpm":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"label":{"type":"string"},"description":{"type":"string"},"createName":{"type":"string"},"proposed":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"}},"required":["id","name","type"],"additionalProperties":false},{"type":"null"}]},"confirmed":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"},"confirmedAt":{"type":"string"}},"required":["id","name","type","confirmedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["category","taxRateId","revenueCategoryId","revenueCategoryName","taxRateName","taxRatePpm","label","description","createName","proposed","confirmed"],"additionalProperties":false}}},"required":["complete","missingCount","accounts","rows"],"additionalProperties":false}},"required":["map"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"confirmAccountingMap","summary":"Confirm QuickBooks account selections","description":"Confirms a set of chart accounts for journal categories. Guessing is forbidden. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","enum":["income.class","income.session","income.space","income.membership","income.pack","income.product","income.other","income.revenue_category","income.booking_fee","income.uncategorized","liability.sales_tax","expense.stripe_fees","expense.booking_fees","expense.disputes","expense.dispute_fees","expense.stripe_other","clearing.stripe","clearing.trx","expense.trx_fees","asset.cash_on_hand","asset.bank"]},"taxRateId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"revenueCategoryId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"externalAccountId":{"type":"string"}},"required":["category","externalAccountId"]}}},"required":["rows"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"map":{"type":"object","properties":{"complete":{"type":"boolean"},"missingCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"}},"required":["id","name","type"],"additionalProperties":false}},"rows":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","enum":["income.class","income.session","income.space","income.membership","income.pack","income.product","income.other","income.revenue_category","income.booking_fee","income.uncategorized","liability.sales_tax","expense.stripe_fees","expense.booking_fees","expense.disputes","expense.dispute_fees","expense.stripe_other","clearing.stripe","clearing.trx","expense.trx_fees","asset.cash_on_hand","asset.bank"]},"taxRateId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"revenueCategoryId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Set on income.revenue_category rows — one account per revenue category, as sales tax is one per rate (architecture/31)."},"revenueCategoryName":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxRateName":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxRatePpm":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"label":{"type":"string"},"description":{"type":"string"},"createName":{"type":"string"},"proposed":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"}},"required":["id","name","type"],"additionalProperties":false},{"type":"null"}]},"confirmed":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"},"confirmedAt":{"type":"string"}},"required":["id","name","type","confirmedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["category","taxRateId","revenueCategoryId","revenueCategoryName","taxRateName","taxRatePpm","label","description","createName","proposed","confirmed"],"additionalProperties":false}}},"required":["complete","missingCount","accounts","rows"],"additionalProperties":false}},"required":["map"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/accounting/map/{category}/create":{"post":{"operationId":"createAccountingMapAccount","summary":"Create a QuickBooks account and confirm it","description":"Creates the account on the connected company with the category's default name (`Sales — Classes`) and confirms the map row. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/AccountingCategoryParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"taxRateId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"revenueCategoryId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"name":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"map":{"type":"object","properties":{"complete":{"type":"boolean"},"missingCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"}},"required":["id","name","type"],"additionalProperties":false}},"rows":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","enum":["income.class","income.session","income.space","income.membership","income.pack","income.product","income.other","income.revenue_category","income.booking_fee","income.uncategorized","liability.sales_tax","expense.stripe_fees","expense.booking_fees","expense.disputes","expense.dispute_fees","expense.stripe_other","clearing.stripe","clearing.trx","expense.trx_fees","asset.cash_on_hand","asset.bank"]},"taxRateId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"revenueCategoryId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Set on income.revenue_category rows — one account per revenue category, as sales tax is one per rate (architecture/31)."},"revenueCategoryName":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxRateName":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxRatePpm":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"label":{"type":"string"},"description":{"type":"string"},"createName":{"type":"string"},"proposed":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"}},"required":["id","name","type"],"additionalProperties":false},{"type":"null"}]},"confirmed":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"subType":{"type":"string"},"confirmedAt":{"type":"string"}},"required":["id","name","type","confirmedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["category","taxRateId","revenueCategoryId","revenueCategoryName","taxRateName","taxRatePpm","label","description","createName","proposed","confirmed"],"additionalProperties":false}}},"required":["complete","missingCount","accounts","rows"],"additionalProperties":false}},"required":["map"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/accounting/postings":{"get":{"operationId":"listAccountingPostings","summary":"List recent QuickBooks postings","description":"Last 30 posting attempts for the live connection: date, kind, amount, status, and the QuickBooks URL when posted. Cursor pages older rows. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"cursor","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"postings":{"type":"array","items":{"type":"object","properties":{"batchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"localDate":{"type":"string"},"kind":{"type":"string","enum":["journal_entry","deposit"]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","posted","failed","skipped"]},"skipReason":{"anyOf":[{"type":"string","enum":["before_start_date","currency_not_home","map_incomplete","disconnected"]},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"postedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["batchId","localDate","kind","amount","currency","status","skipReason","lastError","externalUrl","postedAt"],"additionalProperties":false}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["postings","nextCursor"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/accounting/postings/{batchId}/retry":{"post":{"operationId":"retryAccountingPosting","summary":"Retry a failed QuickBooks posting","description":"Re-enqueues post_journal_batch for the batch. The unique posting row makes a second document impossible. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/JournalBatchIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"queued":{"type":"boolean","const":true}},"required":["queued"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/agreements":{"get":{"operationId":"listAgreements","summary":"List a location's waivers & terms","description":"List a location's waivers & terms Requires feature `location.view`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AgreementDocument"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createAgreement","summary":"Add a waiver or terms document","description":"JSON with `body` for a text document, or multipart/form-data with the same fields beside a PDF `file`. Every asked document is required to book; `everyListing` (default true) puts it on every listing at the location. Requires feature `catalog.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgreementBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AgreementDocument"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/agreements/{documentId}":{"patch":{"operationId":"updateAgreement","summary":"Change a waiver or terms document","description":"Changing the words or the file writes a new copy; earlier copies stay so a customer record opens what was agreed to. `reask: true` asks everyone again at their next booking. Requires feature `catalog.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"},{"in":"path","name":"documentId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgreementBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AgreementDocument"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/agreements/{documentId}/archive":{"post":{"operationId":"archiveAgreement","summary":"Remove a waiver or terms document","description":"Takes it off every listing. The agreements already on customer records are kept, and a copy agreed to still opens. Requires feature `catalog.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"},{"in":"path","name":"documentId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"archived":{"type":"boolean"}},"required":["archived"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/agreements":{"get":{"operationId":"getCartAgreements","summary":"What the signed-in customer has agreed to, for this cart","description":"Of the waivers & terms this cart asks for: the ones the caller still needs to agree to, and the ones they already have, with the date. Scoped to the caller's own record with this business — the cart token alone does not read it. A guest is asked for the cart's whole `agreements` set.","tags":["storefront"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"toAccept":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"description":"The copy shown — what an agreement names.","$ref":"#/components/schemas/Uuid"},"show":{"type":"string","enum":["list","popup","full"]},"frequency":{"type":"string","enum":["once","every_booking"]},"format":{"type":"string","enum":["plain","markdown"]},"body":{"description":"The words, for a popup or full document.","anyOf":[{"type":"string"},{"type":"null"}]},"pageCount":{"description":"A PDF's pages, when known.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"itemIds":{"description":"The cart's items that ask it (the cart view).","type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["id","name","kind","path","contentId","show","frequency"],"additionalProperties":false}},"agreed":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"description":"The copy shown — what an agreement names.","$ref":"#/components/schemas/Uuid"},"show":{"type":"string","enum":["list","popup","full"]},"frequency":{"type":"string","enum":["once","every_booking"]},"format":{"type":"string","enum":["plain","markdown"]},"body":{"description":"The words, for a popup or full document.","anyOf":[{"type":"string"},{"type":"null"}]},"pageCount":{"description":"A PDF's pages, when known.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"itemIds":{"description":"The cart's items that ask it (the cart view).","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"acceptedAt":{"type":"string"}},"required":["id","name","kind","path","contentId","show","frequency","acceptedAt"],"additionalProperties":false}}},"required":["toAccept","agreed"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{offeringId}/agreements":{"get":{"operationId":"getListingAgreements","summary":"What the signed-in customer has agreed to, for this listing","description":"Of the once documents this listing asks for, the ones the caller already holds a current acceptance for, with the date — so the listing page opens only the pop-ups that are new (build-plan/222). An every-booking document is never listed. Scoped to the caller's own record with the listing's business.","tags":["storefront"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"offeringId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"agreed":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"acceptedAt":{"type":"string"}},"required":["id","acceptedAt"],"additionalProperties":false}}},"required":["agreed"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/agreements":{"get":{"operationId":"listCustomerAgreements","summary":"A customer's waivers & terms at a location","description":"What the customer has agreed to at the location, and what is still expected of them: a once document a listing they are booked into asks, and an every-booking document an upcoming booking still needs. Requires feature `crm.view`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"documentId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"status":{"type":"string","enum":["agreed","not_agreed"]},"acceptedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"anyOf":[{"type":"string","enum":["checkout","staff"]},{"type":"null"}]},"recordedByName":{"anyOf":[{"type":"string"},{"type":"null"}]},"shown":{"anyOf":[{"type":"string","enum":["checkbox","full"]},{"type":"null"}],"description":"How the words were in front of them: read in full to the end, or the box. Null for paper and for acceptances before must-reads."},"viewPath":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opens the exact copy agreed to."},"frequency":{"type":"string","enum":["once","every_booking"],"description":"every_booking: not_agreed means an upcoming booking still needs it."}},"required":["documentId","name","kind","status","acceptedAt","source","recordedByName","shown","viewPath","frequency"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/agreements/{documentId}/mark-signed":{"post":{"operationId":"markCustomerAgreementSigned","summary":"Mark a document as signed on paper","description":"Records an acceptance against the current copy under the operator's name. An every-booking document is marked for `bookingId`, else for each upcoming booking that still needs it. Idempotent while the acceptance still counts. Requires feature `crm.notes`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"},{"in":"path","name":"documentId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"bookingId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"documentId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"status":{"type":"string","enum":["agreed","not_agreed"]},"acceptedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"anyOf":[{"type":"string","enum":["checkout","staff"]},{"type":"null"}]},"recordedByName":{"anyOf":[{"type":"string"},{"type":"null"}]},"shown":{"anyOf":[{"type":"string","enum":["checkbox","full"]},{"type":"null"}],"description":"How the words were in front of them: read in full to the end, or the box. Null for paper and for acceptances before must-reads."},"viewPath":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opens the exact copy agreed to."},"frequency":{"type":"string","enum":["once","every_booking"],"description":"every_booking: not_agreed means an upcoming booking still needs it."}},"required":["documentId","name","kind","status","acceptedAt","source","recordedByName","shown","viewPath","frequency"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/assets":{"get":{"operationId":"listAssets","summary":"List photos","description":"Lists the business’s photos, with search, tag, unused, and sort filters. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"tag","schema":{"type":"string"}},{"in":"query","name":"unused","schema":{"type":"string","enum":["1","true"]}},{"in":"query","name":"archived","schema":{"type":"string","enum":["1","true"]}},{"in":"query","name":"sort","schema":{"type":"string","enum":["recent","used","name"]}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AssetListResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"uploadAsset","summary":"Upload a photo","description":"Uploads a photo to Photos without attaching it. Identical bytes return the existing asset. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Asset"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/assets/{id}":{"get":{"operationId":"getAsset","summary":"Get a photo","description":"Returns a photo, its usage count, and the records it is attached to. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/AssetIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AssetDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateAsset","summary":"Update a photo’s title, alt text or tags","description":"Updates a photo title, alt text, or tags. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/AssetIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAssetBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Asset"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteAsset","summary":"Delete a photo","description":"Permanently deletes a photo, its placements, and stored variant objects. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/AssetIdParam"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/assets/{id}/archive":{"post":{"operationId":"archiveAsset","summary":"Archive a photo","description":"Soft-archives a photo so it no longer appears in the picker. Placements keep rendering. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/AssetIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Asset"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/assets/{id}/replace":{"post":{"operationId":"replaceAsset","summary":"Replace a photo’s file","description":"Replaces the bytes of a photo. Existing placements keep the same asset id. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/AssetIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Asset"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/images/attach":{"post":{"operationId":"attachOfferingImage","summary":"Attach a photo to an offering","description":"Attaches an existing photo to an offering. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/resources/{id}/images/attach":{"post":{"operationId":"attachResourceImage","summary":"Attach a photo to a space","description":"Attaches an existing photo to a space. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/instructor-profiles/{id}/images/attach":{"post":{"operationId":"attachInstructorImage","summary":"Attach a photo as an instructor headshot","description":"Attaches an existing photo as an instructor headshot. Requires feature `team.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/membership-plans/{id}/images/attach":{"post":{"operationId":"attachMembershipPlanImage","summary":"Attach a photo as a plan cover","description":"Attaches an existing photo as a membership plan cover. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/MembershipPlanIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/images/attach":{"post":{"operationId":"attachLocationImage","summary":"Attach a photo to a location","description":"Attaches an existing photo to a location. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/logo/attach":{"post":{"operationId":"attachLocationLogo","summary":"Attach a photo as the location logo","description":"Attaches an existing photo as the location logo. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/header/attach":{"post":{"operationId":"attachLocationHeader","summary":"Attach a photo as the location header image","description":"Attaches an existing photo as the location header image, replacing any other. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports":{"post":{"operationId":"createBookingImport","summary":"Start a booking import","description":"Makes the run from the file’s header row and its first rows (≤20; the browser holds the file). Answers the system the headers say (Acuity), the first mapping — the last run’s choices when an earlier file had exactly these headers, else the system’s preset and the column names, then the model for a required field still open — and the time check of the sample. `locationId` defaults to the request’s location, else the business’s first. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"sample":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"locationId":{"$ref":"#/components/schemas/Uuid"}},"required":["headers"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportCreated"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/latest":{"get":{"operationId":"getLatestBookingImport","summary":"The latest booking import","description":"The business’s newest run, or null — the File screen’s *Last import* card. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"run":{"anyOf":[{"$ref":"#/components/schemas/BookingImportRun"},{"type":"null"}]}},"required":["run"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/sample.csv":{"get":{"operationId":"getBookingImportSample","summary":"The booking import’s sample file","description":"A CSV with the columns the import reads, under their labels (they map back by name), and three example rows — for an export that needs reshaping in a spreadsheet first. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"CSV file contents"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/{importId}":{"get":{"operationId":"getBookingImport","summary":"Get a booking import","description":"The run — its choices, counts, flags and status — and its open questions (Needs you). Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingImportIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/BookingImportRun"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/BookingImportIssue"}}},"required":["run","issues"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"patchBookingImport","summary":"Save a booking import’s choices","description":"Saves the choices (each key given replaces the run’s), then makes what they say to make: team members added by email (they get the Team page’s invite; needs `team.manage`), rooms, and listings — hidden, with their hosts (needs `catalog.manage`). A made thing’s choice becomes its id, so a second PATCH makes nothing twice. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingImportIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mapping":{"type":"object","properties":{"columns":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string","enum":["email","phone","givenName","familyName","name","start","date","startTime","end","lengthMinutes","timeZone","listing","teamMember","location","people","price","paid","paymentStatus","bookingId","status","notes"]},{"type":"string","const":""}]},"description":"Header → field; \"\" is Don’t import. Notes may be several headers’."},"time":{"$ref":"#/components/schemas/BookingImportTimeMapping"},"listings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"listingId":{"$ref":"#/components/schemas/Uuid"},"made":{"type":"boolean","const":true}},"required":["listingId"]},{"type":"object","properties":{"create":{"type":"object","properties":{"type":{"type":"string","enum":["class","session","space"]},"name":{"type":"string"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"priceAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units."},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"slotGranularityMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hostValues":{"type":"array","items":{"type":"string"}}},"required":["type","name","durationMinutes","priceAmount","capacity","slotGranularityMinutes"]}},"required":["create"]},{"type":"object","properties":{"skip":{"type":"boolean","const":true}},"required":["skip"]}]}},"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"personId":{"$ref":"#/components/schemas/Uuid"},"added":{"type":"boolean","const":true}},"required":["personId"]},{"type":"object","properties":{"owner":{"type":"boolean","const":true}},"required":["owner"]},{"type":"object","properties":{"add":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"}},"required":["email","name"]}},"required":["add"]},{"type":"object","properties":{"resourceId":{"$ref":"#/components/schemas/Uuid"},"made":{"type":"boolean","const":true}},"required":["resourceId"]},{"type":"object","properties":{"addRoom":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}},"required":["addRoom"]},{"type":"object","properties":{"skip":{"type":"boolean","const":true}},"required":["skip"]}]}},"locations":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"}},"required":["locationId"]},{"type":"object","properties":{"skip":{"type":"boolean","const":true}},"required":["skip"]}]}},"sendReminders":{"type":"boolean"},"aiColumns":{"type":"array","items":{"type":"string"}}}}},"required":["mapping"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportPatched"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/{importId}/read-times":{"post":{"operationId":"readBookingImportTimes","summary":"Check how a booking import reads its times","description":"The time check: the rows’ time cells read under the run’s settings with the request’s changes (zone, day order, format), in the run’s location — how many read, the day order the column settles, where the zone came from, three samples and the rows that did not read. Never a write. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingImportIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"array","items":{"type":"object","properties":{"start":{"type":"string"},"date":{"type":"string"},"startTime":{"type":"string"},"end":{"type":"string"},"lengthMinutes":{"type":"string"},"timeZone":{"type":"string"}}}},"settings":{"type":"object","properties":{"zone":{"type":"string","description":"IANA zone for times that name none (Times are in)."},"dayFirst":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Day/month order; null lets the column decide."},"format":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A pattern from the known list, tried first; null for none."}}}},"required":["values"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportTimeShare"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/{importId}/match-listings":{"post":{"operationId":"matchBookingImportListings","summary":"Match a booking import’s listings and people","description":"Each Listing value by name, then the model, with what its rows say (kind, length, price, seats, grid, hosts); each Team member value to a team member, a room or — on a team of one — you; each Location value by name. The model may only answer with this business’s ids. Never a write. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingImportIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rows":{"type":"array","items":{"type":"object","properties":{"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["fields"]}}},"required":["value"]}},"people":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["value"]}},"locations":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["value"]}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportMatch"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/{importId}/rows":{"post":{"operationId":"importBookingRows","summary":"Import a chunk of booking rows","description":"At most 100 mapped rows, in start order; each row is its own transaction and comes back as one outcome (added · updated · unchanged · held · needs_you · skipped) with its flags. The import never refuses what the other system sold: a full date, a busy host, a closed hour and a class with no date are written and flagged. The file asserts a booking’s state — a row already here (by the system’s method and Booking ID, else customer + listing + date) is moved, resized, re-noted or canceled quietly. `done: true` on the last chunk finishes the run. A retried chunk changes nothing. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingImportIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"minItems":1,"maxItems":100,"type":"array","items":{"$ref":"#/components/schemas/BookingImportRow"}},"done":{"type":"boolean"}},"required":["rows"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportRowsResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/{importId}/issues/{issueId}/resolve":{"post":{"operationId":"resolveBookingImportIssue","summary":"Answer a booking import question","description":"A contact (nobody to reach), a start (a time that did not read) or Hold the seat (a claim with the name on the board) runs the question’s rows through the row rule at once; `all: true` answers every open question of the kind. The run comes back with them. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingImportIdParam"},{"$ref":"#/components/parameters/BookingImportIssueIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"answer":{"anyOf":[{"type":"object","properties":{"contact":{"type":"object","properties":{"email":{"type":"string"},"phone":{"type":"string"}}}},"required":["contact"]},{"type":"object","properties":{"start":{"type":"string","description":"YYYY-MM-DDTHH:MM in the run’s location, or an ISO instant with its zone."}},"required":["start"]},{"type":"object","properties":{"hold":{"type":"boolean","const":true}},"required":["hold"]}]},"all":{"type":"boolean"}},"required":["answer"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportIssueResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/booking-imports/{importId}/issues/{issueId}/skip":{"post":{"operationId":"skipBookingImportIssue","summary":"Skip a booking import question","description":"The question’s rows are skipped; `all: true` skips every open question of the kind. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingImportIdParam"},{"$ref":"#/components/parameters/BookingImportIssueIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"all":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportIssueResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/import-columns":{"post":{"operationId":"importColumnsInline","summary":"Match an import’s columns with the model","description":"The columns still open → booking fields, from their names and up to three example rows. One forced tool call whose schema allows only the open headers and the fields still free; an answer outside them is dropped. Answers nothing (`ai: false`) when no model is configured. One model call, under the inline AI limit and the business’s daily allowance. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"headers":{"type":"array","items":{"type":"string"}},"rows":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"open":{"type":"array","items":{"type":"string"}},"taken":{"type":"array","items":{"type":"string","enum":["email","phone","givenName","familyName","name","start","date","startTime","end","lengthMinutes","timeZone","listing","teamMember","location","people","price","paid","paymentStatus","bookingId","status","notes"]}}},"required":["headers"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportColumnsMatch"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/import-listings":{"post":{"operationId":"importListingsInline","summary":"Match an import’s listings and people with the model","description":"The file’s Listing and Team member values → this business’s listings, team members and rooms (read here, never from the request). The tool’s schema allows only the given values and the business’s ids; a value the model is not sure of is left out. Answers nothing when no model is configured. One model call, under the inline AI limit and the business’s daily allowance. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"listings":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["value"]}},"people":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["value"]}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingImportListingsMatch"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses":{"post":{"operationId":"createBusiness","summary":"Create a business and its first location","description":"Registers a new business and its first location for the signed-in owner. Optional `acceptedLegal: true` records Merchant Agreement and Privacy in the same transaction. Omit it for API/MCP setup — the business cannot take bookings until a person accepts in the console (architecture/18).","tags":["business"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBusinessBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreateBusinessResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"business":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"location":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listBusinesses","summary":"List businesses","description":"Lists businesses visible to the caller.","tags":["business"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Business"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}}}}},"/businesses/{businessId}/legal/merchant-agreement/accept":{"post":{"operationId":"acceptMerchantAgreement","summary":"Accept the current Merchant Agreement and Privacy Policy","description":"Records acceptance of the current Merchant Agreement and Privacy Policy for a business (one-time, or again after a version change). Session only — not callable with an API key. Returns the updated merchantAgreement status. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"stale":{"type":"boolean"},"updateOffered":{"type":"boolean"},"currentVersion":{"type":"string"},"currentSummary":{"type":"string"},"currentEffectiveAt":{"type":"string"},"acceptedVersion":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["stale","updateOffered","currentVersion","currentSummary","currentEffectiveAt","acceptedVersion"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{id}":{"get":{"operationId":"getBusiness","summary":"Get a business by ID","description":"Returns a single business profile by ID.","tags":["business"],"parameters":[{"$ref":"#/components/parameters/BusinessIdPathParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Business"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateBusiness","summary":"Update a business","description":"Updates mutable business profile fields. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdPathParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBusinessBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Business"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{id}/archive":{"post":{"operationId":"archiveBusiness","summary":"Archive a business","description":"Soft-archives a business so it no longer accepts new activity. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdPathParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Business"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{id}/slug":{"patch":{"operationId":"updateBusinessSlug","summary":"Override the business slug","description":"Writes the previous slug to history (old links 301). Renaming the business never changes the slug. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdPathParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"}},"required":["slug"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Business"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{id}/slug/revert":{"post":{"operationId":"revertBusinessSlug","summary":"Revert a business slug to auto-generated from the current name","description":"Revert a business slug to auto-generated from the current name Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdPathParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Business"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{id}/message-preview":{"post":{"operationId":"previewStudioMessage","summary":"Preview unsaved customer-facing words","description":"The letter or sentence the drafts would produce. Nothing is stored. `key` names the message; `scope` is `business` or `location`. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdPathParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"scope":{"type":"string","enum":["business","location"]},"drafts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["key"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"html":{"anyOf":[{"type":"string"},{"type":"null"}]},"subject":{"anyOf":[{"type":"string"},{"type":"null"}]},"sentence":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["html","subject","sentence"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{id}/message-changes":{"get":{"operationId":"listStudioMessageChanges","summary":"Who last changed each customer-facing line","description":"Who last changed each customer-facing line Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdPathParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"scope":{"type":"string","enum":["business","location"]},"subjectId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"key":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"actorName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["scope","subjectId","key","at","actorName"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/api-keys":{"post":{"operationId":"createApiKey","summary":"Create an API key","description":"Issues a business-scoped `bk_` key. The plaintext key is returned once and never again. Session auth only — API keys cannot mint successors. Pass `channelId` to bind the key to one entry under Sold at: it may then only mark, change, or release spots sold there (and read availability). Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1},"channelId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["label"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"apiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"label":{"type":"string"},"channelId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"channelName":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdBy":{"type":"object","properties":{"personId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["personId","name"],"additionalProperties":false},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id","label","channelId","channelName","createdBy","lastUsedAt","createdAt","revokedAt"],"additionalProperties":false},"key":{"type":"string"}},"required":["apiKey","key"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listApiKeys","summary":"List API keys","description":"Metadata only — never the hash or plaintext. Session auth only. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"label":{"type":"string"},"channelId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"channelName":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdBy":{"type":"object","properties":{"personId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["personId","name"],"additionalProperties":false},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id","label","channelId","channelName","createdBy","lastUsedAt","createdAt","revokedAt"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/api-keys/{id}":{"delete":{"operationId":"revokeApiKey","summary":"Revoke an API key","description":"Sets revoked_at. Scoped to the business in the path (IDOR-safe). Session auth only. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ApiKeyIdParam"}],"responses":{"204":{"description":"No content"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings":{"post":{"operationId":"createBooking","summary":"Create a booking hold","description":"Places a capacity hold and returns a booking in held status. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Booking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listBookings","summary":"List bookings for the operator console","description":"Location-scoped roster of bookings that start in [from, to) (local calendar days in the location timezone). Empty days are omitted. Includes canceled bookings unless status is set. Default (no status) omits canceled-with-removed_from_cart and held cart rows whose hold has lapsed; an explicit status filter still returns them. Optional filters: status, offeringId, instructorId (business-scoped callers only — instructor scope always forces the caller's own profile), q (customer name/email, offering name, or booking id prefix), atStep (bookings whose latest done manual or closing step is this journey step, including a partial mark), owes=1 (confirmed or completed bookings with an amount still due — the console's Balance due / Past due rule). Rows carry the snapshotted checkout answers (keyed by questionId) and the customer's phone. Instructor filtering uses the instructors saved on the booked time. Paged instead of windowed when limit is given (1–200; from/to are then ignored): every matching booking in session order, limit at a time, from offset — or, without an offset, from the first booking of day (today in the location timezone), or the last page when nothing starts that late. A shorter remainder stays short. The result then carries page { offset, limit, total } and no from/to. readyPieces=1 (a windowed list with q only — Find a booking's counter, build-plan/277): also the bookings q matches (by name, email, or the last four of the reference a piece is marked with) that have live pieces on Ready, whatever their date — the six most recent sessions, each once, so a day before from can appear — and every row with pieces on Ready carries piecesReady { count, shelves, covers, readyPieceIds }. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"string","pattern":"^\\d+$"}},{"in":"query","name":"offset","schema":{"type":"string","pattern":"^\\d+$"}},{"in":"query","name":"day","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string","enum":["held","confirmed","checked_in","checked_out","completed","canceled","no_show"]}},{"in":"query","name":"offeringId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"instructorId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"customerId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"atStep","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"owes","schema":{"type":"string","enum":["1","true"]}},{"in":"query","name":"readyPieces","schema":{"type":"string","enum":["1","true"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBookingListResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/availability":{"get":{"operationId":"getOperatorAvailability","summary":"List bookable dates and times for operators (includes past-cutoff, in-progress, and closed starts)","description":"Closed starts stay in the list with closedBy set to the closure’s words. The public availability route does not. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"offeringId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"instructorId","schema":{"description":"Reservations: read one team member's slots instead of the whole pool.","$ref":"#/components/schemas/Uuid"},"description":"Reservations: read one team member's slots instead of the whole pool."},{"in":"query","name":"from","schema":{"type":"string"},"required":true},{"in":"query","name":"to","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"occurrenceId":{"type":"string","description":"Stable moment key. Classes: `scheduleId:startUtc`. Reservations and rentals: `offeringId:subjectId:startUtc`, where the subject is the team member (reservation) or space (rental); `any` in place of the subject is a customer's open pick that the hold resolves in pool order."},"scheduleId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"The class schedule projected; null for reservation and rental grids."},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"localStart":{"type":"string"},"localEnd":{"type":"string"},"timezone":{"type":"string"},"capacityTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacityRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxPartySize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Largest party a table can still take, capped by the seats left. 0 reads full. Null when the room has no tables, or the listing sells the whole space."},"capacityByStatus":{"$ref":"#/components/schemas/ScheduleCapacityByStatus"},"status":{"type":"string","enum":["open","full","blacked_out","closed"]},"materialized":{"type":"boolean"},"instructorIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"Reservations only: team members who can take this start. The occurrenceId names one of them when exactly one is free, else `any`. Empty for classes and rentals."},"stranded":{"$ref":"#/components/schemas/StrandedReason"},"closedBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The first closure over this start, in the Calendar’s words — Closed · block, Closed 9–10 AM · Out of Town, Loft closed · Floor refinish, Sam off · dentist, Busy · Sam’s Google Calendar — or null when the start is open."}},"required":["occurrenceId","scheduleId","startsAt","endsAt","localStart","localEnd","timezone","capacityTotal","capacityRemaining","maxPartySize","capacityByStatus","status","materialized","instructorIds","stranded","closedBy"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/carts":{"post":{"operationId":"createOperatorCart","summary":"Create an operator pay-by-link cart","description":"Creates a cart for a customer with held booking items and returns the absolute cart URL. Requires Connect charges-enabled. Provide customerId or email (find-or-create). Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOperatorCartBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PayLinkCart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/carts/{token}/checkout":{"post":{"operationId":"checkoutOperatorCart","summary":"Check out an operator cart at the desk","description":"Manual capture of a staff cart — Paid at the desk. Gated on `expectedEffect` (`cart.checkout`). The attached customer is the payer, never the operator. `answers` are what the desk asked: validated like the storefront's, but a required question left open never refuses the sale. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CartTokenParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","const":"manual"},"answers":{"type":"array","items":{"type":"object","properties":{"questionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"]}]}},"required":["questionId","value"]}},"expectedEffect":{"type":"object","properties":{"currency":{"type":"string"},"movements":{"type":"array","items":{"type":"object","properties":{"direction":{"type":"string","enum":["charge","refund","forfeit"]},"instrument":{"type":"string","enum":["card","cash","credits"]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["direction","instrument","amount"]}}},"required":["currency","movements"]}},"required":["provider","expectedEffect"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PayLinkCart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/carts/{token}/cancel":{"post":{"operationId":"cancelOperatorCart","summary":"Cancel a staff cart and release its holds","description":"Revokes an open staff cart (the desk dismissed the money dialog). Storefront carts are refused. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CartTokenParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PayLinkCart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/carts/{token}/email":{"post":{"operationId":"sendOperatorCartPayLink","summary":"Email a pay link to the cart customer","description":"Sends the pay-link email to the cart's attached customer. Transactional (ignores marketing consent). Returns { sent, toMasked } — or sent:false with a reason when there is no recipient, the cart is not open, or mail is not configured. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CartTokenParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PayLinkEmailResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/agreements/send":{"post":{"operationId":"sendBookingAgreements","summary":"Send the customer a link to accept the booking's waivers & terms","description":"One link asks for everything the booking still needs, one Accept at a time (build-plan/286). channel email goes to `to` when given (this send only, never saved) else the customer's email; sms only to the customer's own number when they agreed to texts on it (409 no_text otherwise); copy sends nothing and returns the link as `url`. 409 nothing_left when everything is agreed, ended once the booking's date ended + 15 minutes. Rate limited per booking and per business. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms","copy"]},"to":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["channel"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingAgreementsSendResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/agreements/{documentId}/override":{"post":{"operationId":"overrideBookingAgreement","summary":"Mark one of the booking's waivers & terms agreed","description":"The desk's Override (build-plan/286): recorded under the operator's name against the current copy — a once document for the customer, an every-booking document for this booking. Already agreed changes nothing. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"},{"in":"path","name":"documentId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"agreements":{"anyOf":[{"$ref":"#/components/schemas/BookingAgreements"},{"type":"null"}]}},"required":["agreements"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/pay-link":{"post":{"operationId":"sendBookingPayLink","summary":"Send a held booking its pay link, by email or text","description":"For a held booking: sends the customer the pay link of the cart the hold belongs to, wrapping the hold in a cart first when it has none (no new hold, no second link). channel email (the default) or sms; `to` is an address or number for this send only, never saved to the customer (build-plan/286 — the desk may text any number; a number that replied STOP is 409 no_text). Returns { sent, toMasked, payLink } — or sent:false with a reason when there is no recipient, the cart is not open, or mail is not configured. 400 when the booking is not held. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms"]},"to":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PayLinkEmailResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/export.csv":{"get":{"operationId":"exportBookingsCsv","summary":"Export the bookings list as CSV","description":"A people list, one row per booking (a deposit booking is one row), with the same window, filters and scope as listBookings. basis=session (default) windows on when they come, basis=booked on when they booked; both are local calendar days in the location timezone, half-open. After the fixed columns, one \"q: <prompt>\" column per question the included listings ask (keyed by question id, so a shared question is one column and an unanswered one still has its column). Money in major units with a currency column; not a reconciliation — the Payments exports are. columns= names the columns to include (comma-separated keys from the export catalog, e.g. start_date,start_time,customer_name,space,tables,answers); the file keeps the catalog order, unknown keys are dropped, and without it the standard set is returned. Header cells are words (Start date, Name, …); the answers key expands to one \"q: <prompt>\" column per question. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"from","schema":{"type":"string"},"required":true},{"in":"query","name":"to","schema":{"type":"string"},"required":true},{"in":"query","name":"basis","schema":{"type":"string","enum":["session","booked"]}},{"in":"query","name":"status","schema":{"type":"string","enum":["held","confirmed","checked_in","checked_out","completed","canceled","no_show"]}},{"in":"query","name":"offeringId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"instructorId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"customerId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"owes","schema":{"type":"string","enum":["1","true"]}},{"in":"query","name":"columns","schema":{"type":"string"}}],"responses":{"200":{"description":"CSV file contents","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/page-preview":{"post":{"operationId":"previewLocationPage","summary":"Render the location page with unsaved edits","description":"Your page's live preview (build-plan/135). Returns the **real** location page HTML — the same renderer a customer is served — with the operator's unsaved brand and contact edits layered over fresh data, so a preview cannot drift from the page it shows. Writes nothing. Hours are edited as schedules rather than typed and are not overridable. Requires feature `location.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationPagePreviewBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LocationPagePreviewHtml"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/listing-preview":{"post":{"operationId":"previewListingPage","summary":"Render an offering’s booking page from an unsaved editor form","description":"The class / reservation / space editor's live preview (build-plan/135). Returns the real booking page HTML from the operator's form. `offeringId` is optional: with one, the saved row is read at **any** status — previewing before publishing is the point — and the draft is layered over it; without one the draft is rendered as an offering that does not exist yet, so the page takes shape before the first save. Writes nothing. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingPagePreviewBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingPagePreviewHtml"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/passes-preview":{"post":{"operationId":"previewPassesPage","summary":"Render the passes page with an unsaved plan","description":"The membership / pass editor's live preview (architecture/11). Returns the real passes page HTML with the operator's draft plan swapped in — or added, while it is still being created. `planId` is optional: with one, the saved row is read at any status and the draft is layered over it; without one the draft is rendered as a plan that does not exist yet. `benefits` is the console's JSON string. Writes nothing. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PassesPagePreviewBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PassesPagePreviewHtml"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}":{"get":{"operationId":"getBooking","summary":"Get a booking","description":"Returns booking details including price snapshot and payment state. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"editBooking","summary":"Edit a booking","description":"Edit a booking (build-plan/288): the facts the desk changed, saved together — the customer (their details, or Someone else, keeping the payment), the class, the time, the room (over its seats is taken, warned), how many and the price that follows, the answers, the note. It never changes status, charges or refunds: a change that makes it cost more leaves the difference owed. `price: keep` on a change the price would follow needs `booking.price_keep`; a class’s room is its date’s and needs `catalog.manage`. One `booking.edited` event; with `notify`, one change email. `preview: true` checks it all and writes nothing, answering a BookingEditPreview. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"customer":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"customerId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"type":"string"},"overClosure":{"type":"boolean"},"resourceId":{"$ref":"#/components/schemas/Uuid"},"tableId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"priceSelection":{"minItems":1,"type":"array","items":{"type":"object","properties":{"tierId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"quantity":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["tierId","quantity"]}},"price":{"type":"string","enum":["settle","keep"]},"answers":{"type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"value":{}},"required":["questionId","value"]}},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"notify":{"type":"boolean"},"preview":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/OperatorBooking"},{"$ref":"#/components/schemas/BookingEditPreview"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/confirm":{"post":{"operationId":"confirmBooking","summary":"Confirm a held booking with payment","description":"Captures payment and confirms a held booking. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/collect-balance":{"post":{"operationId":"collectBookingBalance","summary":"Collect remaining booking balance","description":"Charges the remaining balance on a split-pay booking. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectBalanceBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/record-payment":{"post":{"operationId":"recordBookingPayment","summary":"Record a booking as paid through a payment method","description":"Record payment (architecture/24 § Closing out): close out what a booking owes through one of the business's paid-elsewhere payment methods, the method's reference rule applied. A held booking is restated as paid elsewhere and confirmed for $0; a balance due is closed out and the Collect balance step closes. No money moves here — no Payment, no ledger row, nothing in reports or the journal — and it is logged as `booking.paid_elsewhere`. A held booking with add-ons or a payment in flight is refused (pieces are paid here). Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordBookingPaymentBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/answers":{"put":{"operationId":"putBookingAnswers","summary":"Write what the desk asked onto a booking","description":"Questions asked at the desk (architecture/16 § Asked at the desk) for a booking with no cart to check out — paid elsewhere. Only the questions its listing asks are kept; each answer is validated as at checkout, a required one left open is no refusal, and an empty answer writes nothing. Returns every answer the booking now carries. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"answers":{"type":"array","items":{"type":"object","properties":{"questionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"]}]}},"required":["questionId","value"]}}},"required":["answers"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"questionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"prompt":{"type":"string"},"type":{"type":"string"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"],"additionalProperties":false}]}},"required":["questionId","prompt","type","value"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/add-ons":{"get":{"operationId":"listBookingAddOns","summary":"What a booking can still add at the class","description":"For Add to booking on the booking record (architecture/26 § Adding a piece after booking): the listing's optional add-ons, each with its cap (max per spot × spots), what the booking already has, what remains, and each option with its price, units available and one unit all in (tax and the customer fee). `card` is the card the booking saved — null when none. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"bookingId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"currency":{"type":"string"},"card":{"anyOf":[{"type":"object","properties":{"brand":{"type":"string"},"last4":{"type":"string"}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"addOns":{"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"cap":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"already":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"options":{"type":"array","items":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"available":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"amountDueNow":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["variantId","name","priceAmount","available","amountDueNow"],"additionalProperties":false}}},"required":["productId","name","cap","already","remaining","options"],"additionalProperties":false}}},"required":["bookingId","currency","card","addOns"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"addToBooking","summary":"Add pieces to a booking on its saved card","description":"Charges the card the booking saved for optional add-ons picked at the class, priced as a cart line is, gated on `expected_effect` (`booking.add_on`). The stock is held and the charge made off-session; the pieces join the booking when it settles. 402 `card_declined` with Stripe's reason releases the hold; 409 `no_card_on_file` when the booking saved no card. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddToBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/cancel":{"post":{"operationId":"cancelBooking","summary":"Cancel a booking","description":"Cancels a booking and releases capacity. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/enrollments/{enrollmentId}/cancel":{"post":{"operationId":"cancelEnrollment","summary":"Cancel a series enrollment","description":"Cancel a series enrollment Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/EnrollmentIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Enrollment"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/email":{"post":{"operationId":"changeBookingEmail","summary":"Change the email a booking belongs to","description":"Change the email a booking belongs to Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeBookingEmailBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChangeEmailResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/reschedule":{"post":{"operationId":"rescheduleBooking","summary":"Reschedule a booking","description":"Moves a booking to a different date or time of the same offering, or — with `offeringId` — a confirmed class booking to a date of another published class at the same location, or — with `resourceId` — a confirmed room booking (a rental, a buyout of the whole space, or a per-person party hosted by a room) to another room at the same location, at the same time. A rental or a buyout must hold its time alone; a per-person party may move while the others stay on its date. A room must take the booking for its whole window as a hold would: open by its hours, clear of closures and of its Google Calendar, free of other bookings and class dates there, with spots (and a table) for the party; otherwise `409` with `details.reason` `room_taken`, `too_small`, `no_table`, `closed` or `busy`. The booking keeps its id, its price and its payments; nothing is charged or refunded. The listing's cancellation cutoff is the customer's policy and does not bind the desk; capacity and conflicts still do. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescheduleBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Booking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/spots":{"post":{"operationId":"changeBookingSpots","summary":"Change how many spots a booking holds","description":"Changes the spots on a confirmed or checked-in per-spot booking. `price: keep` leaves what was paid. `price: settle` reprices it at today’s price for what it now holds and leaves the difference owed (build-plan/288 D2); a pass, a payment taken elsewhere, or a lower price that would need money back is 409 `keep_only`. A customer cannot call it. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"priceSelection":{"minItems":1,"type":"array","items":{"type":"object","properties":{"tierId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"quantity":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["tierId","quantity"]}},"price":{"type":"string","enum":["keep","settle"]}},"required":["priceSelection","price"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Booking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/places":{"get":{"operationId":"listBookingPlaces","summary":"Where a booking could sit: its room’s tables, and the other rooms","description":"Where a booking could sit: its room’s tables, and the other rooms Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingPlaceChoices"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/rooms":{"get":{"operationId":"listBookingRooms","summary":"Rooms a booking could move to","description":"The rooms Change room offers a confirmed room booking: the room it is in, and every other live room at its location that would take it for its whole window — each tried with the move itself and rolled back, so a room listed here is one `reschedule` with `resourceId` accepts. A rental or a buyout that shares its time is refused; a per-person party among others is not. A class booking, a buyout of a set of tables, or one that has ended is refused. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingRoomChoices"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"current":{"id":"550e8400-e29b-41d4-a716-446655440040","name":"Party Room"},"rooms":[{"id":"550e8400-e29b-41d4-a716-446655440041","name":"Studio","capacity":30}]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/check-in":{"post":{"operationId":"checkInBooking","summary":"Check in a booking (status checked_in)","description":"Checks in a booking (status checked_in) on the day it happens. Another day is 409 not_today. The journey timer is exempt. After the session has ended, Check out runs at once. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckInBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/desk-check-in":{"get":{"operationId":"previewDeskCheckIn","summary":"Preview early check-in stay, tables, and next opening","description":"Returns whether check-in would start the window now (early) or keep the reserved clock, the default stay (the original length from now, or to the reserved end), what has the space next (freeUntil), tables that fit, and when a table next opens if none do. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"},{"in":"query","name":"endsAt","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},{"in":"query","name":"keepStart","schema":{"description":"Early: keep the reserved start — the window as booked, the party marked here.","type":"string","enum":["true","false"]},"description":"Early: keep the reserved start — the window as booked, the party marked here."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DeskCheckInPreview"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"early":true,"canShiftWindow":true,"eligible":true,"reason":null,"originalStartsAt":"2026-10-04T17:00:00.000Z","originalEndsAt":"2026-10-04T18:00:00.000Z","defaultEndsAt":"2026-10-04T14:00:00.000Z","durationMinutes":60,"suggestedTableId":null,"tables":[],"nextOpenAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/check-in-at-desk":{"post":{"operationId":"checkInAtDesk","summary":"Desk check-in (may start now and seat a table)","description":"Desk check-in on the day of the booking (another day is 409 not_today): early, starts the held window now (default stay is the original length); on the reserved clock, keeps it unless endsAt moves the end; seats the party at a table, then marks attended. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckInAtDeskBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/check-out":{"post":{"operationId":"checkOutBooking","summary":"Check out a booking (status checked_out; frees a sole booking's space early)","description":"Checks out a checked-in booking (status checked_out). Before the end, a booking alone on its time frees its space from `at`; a shared class keeps its time. A completed booking returns 409 booking_completed. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckOutBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/undo-check-out":{"post":{"operationId":"undoCheckOut","summary":"Undo check-out (back to checked_in)","description":"Undoes check-out — back to checked_in, restoring the original end. 409 space_taken when that time was rebooked. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/money-effects":{"post":{"operationId":"describeMoneyEffect","summary":"Dry-run: declare the money effect of an action without executing it","description":"Dry-run: declare the money effect of an action without executing it Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["booking.confirm","booking.collect_balance","booking.cancel","booking.complete","payment.refund","membership.record_payment","membership.sell","membership.renew","membership.change_spots","enrollment.cancel","order_line.cancel","order_line.fulfill","cart.checkout","booking.add_on","occurrence.cancel"]},"bookingId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"occurrenceId":{"type":"string"},"paymentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"membershipId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"customerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"planId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"enrollmentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"orderLineId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"cartToken":{"type":"string"},"provider":{"description":"For `membership.sell`: `manual` (paid at the desk) or `card` (the card on file, named in the effect).","type":"string","enum":["stripe","manual","card"]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string","minLength":3,"maxLength":3},"pieces":{"type":"array","items":{"type":"object","properties":{"variantId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"quantity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["variantId","quantity"]}}},"required":["action"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"action":{"type":"string"},"currency":{"type":"string"},"movements":{"type":"array","items":{"type":"object","properties":{"direction":{"type":"string","enum":["charge","refund","forfeit"]},"instrument":{"type":"string","enum":["card","cash","credits"]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"label":{"type":"string"}},"required":["direction","instrument","amount","label"],"additionalProperties":false}},"requiresApproval":{"type":"boolean"},"summary":{"type":"string"},"breakdown":{"description":"Who gets what, one line each — only on actions that settle several people (occurrence.cancel). Display only; never echoed.","type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"detail":{"type":"string"}},"required":["label","detail"],"additionalProperties":false}}},"required":["action","currency","movements","requiresApproval","summary"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/undo-check-in":{"post":{"operationId":"undoCheckIn","summary":"Undo check-in (back to confirmed)","description":"Undoes check-in — returns a checked-in booking to confirmed. Undo the check-out first. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/no-show":{"post":{"operationId":"markBookingNoShow","summary":"Mark a booking as no-show","description":"Marks a confirmed booking as no-show once its time has started (before that, 409 not_started). A booking alone on its time ends then. On a shared tabled slot the party leaves its table; the room still counts them until the booked end. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OperatorBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/positions":{"get":{"operationId":"getOccurrencePositions","summary":"Class date fill map","description":"Positions and occupants for one date. Exclusive or no-space dates return mode=roster. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OccurrencePositionBoard"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440010:2026-09-01T17:00:00.000Z","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Morning Flow","startsAt":"2026-07-24T12:00:00.000Z","endsAt":"2026-08-01T18:00:00.000Z","timezone":"America/Denver","resourceId":"550e8400-e29b-41d4-a716-446655440007","resourceName":"Studio A","exclusive":false,"mode":"positions","positionLayout":"list","capacityTotal":20,"capacityBooked":1,"capacityElsewhere":0,"waitlisted":0,"waitlist":[],"claims":[],"positions":[{"id":"550e8400-e29b-41d4-a716-446655440030","sortIndex":0,"name":"Window","occupant":{"bookingId":"550e8400-e29b-41d4-a716-446655440005","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-07-24T12:00:00.000Z"}}],"unassignedBookings":[],"roster":[{"bookingId":"550e8400-e29b-41d4-a716-446655440005","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-07-24T12:00:00.000Z"}],"share":{"url":"https://placefull.ai/downtown/morning-flow?time=550e8400-e29b-41d4-a716-446655440010%3A2026-09-01T17%3A00%3A00.000Z","details":"A slow, steady flow to start the day.","imageUrl":null,"place":"Downtown, 123 Main St, Denver, CO"}},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/waitlist/{entryId}":{"delete":{"operationId":"removeOccurrenceWaitlistPlace","summary":"Take someone off a class date's waitlist","description":"The desk removes a place the date's board lists — the date's own line, or a subscription's line for its weekly time. A place that was offered gives its spot back and the next in line is offered it. Answers the board. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"},{"$ref":"#/components/parameters/EntryIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OccurrencePositionBoard"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/table":{"post":{"operationId":"moveBookingTable","summary":"Move a party to another table","description":"Seats the party on another table in the same room, or splits it over the tables named in `tables` (their seats must add up to the party). Refused when a table is not free for the booking's entire time. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"tableId":{"$ref":"#/components/schemas/Uuid"}},"required":["tableId"]},{"type":"object","properties":{"tables":{"minItems":1,"type":"array","items":{"type":"object","properties":{"tableId":{"$ref":"#/components/schemas/Uuid"},"seats":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["tableId","seats"]}}},"required":["tables"]}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"bookingId":{"$ref":"#/components/schemas/Uuid"},"tableId":{"$ref":"#/components/schemas/Uuid"},"tableIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["bookingId"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/positions/move":{"post":{"operationId":"moveBookingPosition","summary":"Move, swap, or assign one spot","description":"Moves one booking_positions row to another live spot on the same date. Occupied target swaps. Omit fromPositionId to assign one remaining spot (occupied target claims that spot). Requires booking.checkin. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveBookingPositionBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OccurrencePositionBoard"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440010:2026-09-01T17:00:00.000Z","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Morning Flow","startsAt":"2026-07-24T12:00:00.000Z","endsAt":"2026-08-01T18:00:00.000Z","timezone":"America/Denver","resourceId":"550e8400-e29b-41d4-a716-446655440007","resourceName":"Studio A","exclusive":false,"mode":"positions","positionLayout":"list","capacityTotal":20,"capacityBooked":1,"capacityElsewhere":0,"waitlisted":0,"waitlist":[],"claims":[],"positions":[{"id":"550e8400-e29b-41d4-a716-446655440030","sortIndex":0,"name":"Window","occupant":{"bookingId":"550e8400-e29b-41d4-a716-446655440005","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-07-24T12:00:00.000Z"}}],"unassignedBookings":[],"roster":[{"bookingId":"550e8400-e29b-41d4-a716-446655440005","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-07-24T12:00:00.000Z"}],"share":{"url":"https://placefull.ai/downtown/morning-flow?time=550e8400-e29b-41d4-a716-446655440010%3A2026-09-01T17%3A00%3A00.000Z","details":"A slow, steady flow to start the day.","imageUrl":null,"place":"Downtown, 123 Main St, Denver, CO"}},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/message":{"post":{"operationId":"sendOccurrenceMessage","summary":"Email everyone booked on this date","description":"Queues a transactional class note to the roster (held / confirmed / checked in) who have an email. Does not consult marketing consent. Requires booking.checkin. Empty roster or no emails is 400. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OccurrenceMessageBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OccurrenceMessageResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"batchId":"550e8400-e29b-41d4-a716-446655440040","queued":4,"skippedNoEmail":0,"subject":"Morning Flow · Monday, August 31, 10:00 AM","channels":["email","wallet"],"walletHolders":3},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/wallet-notes":{"post":{"operationId":"postWalletNote","summary":"Message Wallet holders","description":"A studio-wide note (build-plan/262): lands on the back of every studio card and every ticket for a class still to come that is held in Apple or Google Wallet, and notifies each holder once. Plain text; title ≤ 60, message ≤ 500. Only important studio news — Wallet notifications are not for promotions. Requires crm.notes. Requires feature `crm.notes`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletNoteBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WalletNoteResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/channels":{"get":{"operationId":"listChannels","summary":"List where spots are sold elsewhere","description":"Live channels for this business. The console suggestion list (At the door, Square, …) is client-side and created on first use. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}},"required":["channels"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createChannel","summary":"Add where spots are sold elsewhere","description":"Creates a channel row. A duplicate name answers 409 channel_exists with the existing id so the console can reuse it. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannelBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Channel"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/channels/{channelId}":{"patch":{"operationId":"updateChannel","summary":"Rename or archive where spots are sold elsewhere","description":"Rename is case-insensitive unique among live rows. Archive hides the row from the picker; existing claims keep the name. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ChannelIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChannelBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Channel"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/claims":{"get":{"operationId":"listOccurrenceClaims","summary":"List spots sold elsewhere on this date","description":"Unreleased claims for the host board. Requires booking.view. Instructor scope is the same as the fill map. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"claims":{"type":"array","items":{"$ref":"#/components/schemas/ChannelClaim"}}},"required":["claims"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createOccurrenceClaim","summary":"Mark spots sold elsewhere","description":"Takes N spots through a channel. Returns 201, or 200 when externalRef is already claimed. 409 sold_out or session_ended. Requires booking.checkin. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClaimBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChannelClaimWithWarnings"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/channels/{channelId}/claims/by-ref/{externalRef}":{"put":{"operationId":"syncClaimByRef","summary":"Sync spots sold elsewhere by reference","description":"One idempotent call per event in the other system. No live claim + `seats` ≥ 1 → created (201). Same date → updated / unchanged; `seats` 0 → released; another date → moved (release + create). Address the date by our occurrenceId or by offeringId/listingSlug + localStart. Accepts a channel-bound key. Requires booking.checkin. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ChannelIdParam"},{"$ref":"#/components/parameters/ExternalRefParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncClaimBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimSyncResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/channels/{channelId}/claims/sync":{"post":{"operationId":"syncClaims","summary":"Sync many spots sold elsewhere at once","description":"Up to 200 items with the same semantics as sync-by-reference, applied one at a time with per-item outcomes — a sold_out item never blocks its siblings. Accepts a channel-bound key. Requires booking.checkin. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ChannelIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncClaimsBatchBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ClaimSyncBatchResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/claims/{claimId}":{"patch":{"operationId":"updateClaim","summary":"Edit spots sold elsewhere","description":"More spots re-runs the capacity guard. Fewer never fails. Requires booking.checkin. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ClaimIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClaimBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChannelClaim"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"releaseClaim","summary":"Release spots sold elsewhere","description":"Sets released_at. Freed capacity triggers waitlist promotion. Requires booking.checkin. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ClaimIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChannelClaim"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/stripe/connect-account":{"post":{"operationId":"createStripeConnectAccount","summary":"Create a Stripe Connect account for the business","description":"Prefills onboarding from the business profile. `entityType` (asked once in the console) sets Stripe `business_type` and, for `individual`, prefills the caller as the representative from their person record's legal name. Omit it to let Stripe ask. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"entityType":{"type":"string","enum":["individual","company"]}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Business"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/stripe/sandbox-account":{"post":{"operationId":"provisionSandboxStripeAccount","summary":"Create a verified Stripe test account (development and staging only)","description":"Skips embedded KYC by creating a Custom connected account with Stripe test tokens. 403 in production, and 403 against a live secret key. An unfinished account is replaced. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Business"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/stripe/account-session":{"post":{"operationId":"createStripeAccountSession","summary":"Create a Stripe Account Session for embedded onboarding","description":"Returns a Stripe client secret for embedded Connect onboarding. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConnectAccountSession"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"clientSecret":"acs_example_client_secret","publishableKey":"pk_example","stripeAccountId":"acct_example"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/stripe/status":{"get":{"operationId":"getStripeConnectStatus","summary":"Get the Stripe Connect onboarding status for the business","description":"Get the Stripe Connect onboarding status for the business Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConnectStatus"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/status":{"get":{"operationId":"getPaymentsStatus","summary":"The business's payments provider and whether it can take cards now","description":"`{ provider, ready }` with the provider's own status under its name: `stripe` carries the Connect status (the same shape as GET …/stripe/status); `trx` carries the masked merchant record, or null before one is written. The console reads this before rendering anything provider-shaped (build-plan/200). Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentsStatus"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"provider":"stripe","ready":true,"stripe":{"state":"connected","stripeAccountId":"acct_example","chargesEnabled":true,"payoutsEnabled":true,"detailsSubmitted":true,"requirementsCurrentlyDue":[],"disabledReason":null,"onboardingStatus":"complete","feeBps":200,"feeMode":"absorb","feeCustomerPct":50,"feeModeImpact":{"classes":14,"sessions":3,"spaces":0},"availableBalance":124050,"pendingBalance":5000,"balanceCurrency":"USD","statementDescriptor":"MDHOLT.COM","payoutBank":{"bankName":"STRIPE TEST BANK","last4":"6789","currency":"USD"}},"capabilities":{"feeMode":true}},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/account":{"delete":{"operationId":"unlinkPaymentsAccount","summary":"Unlink the business's payments account (platform admins only)","description":"Platform admins on their own session; anyone else is refused. Stripe: the business forgets its connected account (`stripe_account_id` null, charges and payouts off, onboarding `not_started`) — nothing is called at Stripe. TRX: the merchant record and its sealed login are deleted; the provider stays `trx`. Payments, refunds and settlement facts are untouched, and a past payment is refunded on the account it was charged on. The storefront stops selling until payments are set up again (unless demo mode is on). 409 when nothing is linked, when memberships still renew on a card saved through the Stripe account, or while a legacy mirror follows a TRX business. Answers the payments status after. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnlinkPaymentsAccountBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentsStatus"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"provider":"stripe","ready":true,"stripe":{"state":"connected","stripeAccountId":"acct_example","chargesEnabled":true,"payoutsEnabled":true,"detailsSubmitted":true,"requirementsCurrentlyDue":[],"disabledReason":null,"onboardingStatus":"complete","feeBps":200,"feeMode":"absorb","feeCustomerPct":50,"feeModeImpact":{"classes":14,"sessions":3,"spaces":0},"availableBalance":124050,"pendingBalance":5000,"balanceCurrency":"USD","statementDescriptor":"MDHOLT.COM","payoutBank":{"bankName":"STRIPE TEST BANK","last4":"6789","currency":"USD"}},"capabilities":{"feeMode":true}},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/demo":{"get":{"operationId":"getDemo","summary":"Demo mode: on or off, whether it can be switched on, and what Clear would delete","description":"Demo mode lets a business that cannot take payments yet try its storefront: every quote owes nothing and every booking, pass and piece written is marked demo (build-plan/209). Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DemoState"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"startDemo","summary":"Switch demo mode on","description":"A Settings → Payments setting: allowed whether or not the business can take payments. While on, every booking and pass on the page is free and demo. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DemoState"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"endDemo","summary":"Switch demo mode off, deleting its data","description":"Demo data never outlives demo mode: this deletes what Clear would, then switches it off. Payments going live does the same. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DemoClearResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/demo/clear":{"post":{"operationId":"clearDemo","summary":"Delete the demo data; demo stays on","description":"Deletes every demo booking, pass and piece and what hangs off them, and the customers the demo made who have nothing real on them. A real pack a demo booking spent from gets its credit back. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DemoClearResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/provider":{"post":{"operationId":"chooseTrxOrStripe","summary":"Choose the business's card processor, Stripe or TRX, before its first payment","description":"Settings → Payments' choice (build-plan/237). Only while the business has no payment, no Stripe account and no TRX record (409 otherwise); `trx` needs TRX applications open (409 `trx_onboarding_closed`). Console session only. Answers the application. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChoosePaymentsProviderBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxApplication"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-application":{"get":{"operationId":"getTrxApplication","summary":"The business's TRX application — status, draft, masked facts","description":"Never a sensitive value: last fours only. Looks the lead up at TRX (Lead/Lookup on the onboarding gateway) when the last look is over ten minutes old. Platform admins also get `admin` — the lead GUID, file GUIDs and the last lookup. Console session only. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxApplication"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"saveTrxApplicationDraft","summary":"Save the non-sensitive half of the TRX application for later","description":"An allowlist: anything sensitive in the body is dropped, never stored. 409 once the application has been sent. Console session only. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrxApplicationDraftBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxApplication"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-application/submit":{"post":{"operationId":"submitTrxApplication","summary":"Send the TRX application: Lead/Insert, then a File/Insert per document","description":"The whole application with its documents (body up to 14 MB). Checked in plain words (400 with each field), sent to TRX over TLS, and dropped: SSN, date of birth, licence, EIN, bank numbers and images are never stored or logged — only TRX’s references, masked last fours and who sent it. The signed application (`application`, required) gets the electronic signature record appended — the server’s time, the client IP and user agent, the consent, the SHA-256 of the signed pages — and goes as `File/Insert` `FileType Agreement`; its record (never the PDF) is kept. One application per business: 409 once sent or while a send is in flight. A document TRX did not take is listed as failed; resend it alone with `…/documents`. 422 `trx_lead_refused` when TRX turns the lead down; 503 when TRX does not answer (nothing is kept). Console session only. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrxApplicationSubmitBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxApplication"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-application/documents":{"post":{"operationId":"resendTrxApplicationDocuments","summary":"Send again only the documents TRX did not take — against the same lead","description":"Never inserts the lead again. 409 for a document TRX already holds. Console session only. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrxApplicationDocumentsBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxApplication"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-pricing":{"get":{"operationId":"getTrxPricing","summary":"The pricing TRX’s merchant application states for the business","description":"Page 2 of the signed application (build-plan/237 ticket 12): the business’s own pricing, set by a platform admin, else the default (TRX_PRICING_DEFAULT_PERCENT / _PER_ITEM — flat 2.9% + 30¢; `isDefault`). The owner reads it. Console session only. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxPricing"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"putTrxPricing","summary":"Set the business’s TRX pricing (platform admins only)","description":"Platform admins on their own session; anyone else is refused. Flat (a discount rate and per-item fee) or interchange plus (a markup and per-item fee, Amex’s own pair optional), and optional batch and chargeback fees — what the application states. It changes nothing at TRX by itself: TRX prices by its pricing profile (TRX_ONBOARDING_PRICING_GUID). Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutTrxPricingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxPricing"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-account":{"get":{"operationId":"getTrxAccount","summary":"The TRX merchant record, masked — or null when the business has none","description":"Every read masks: the password is never returned, the gateway login and the StorageSafe vault come back as their last four. The MID and client id are whole, since a studio quotes them to TRX or its bank. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/TrxAccount"},{"type":"null"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"merchantNumber":"8788290000412","clientId":"412","dba":"Ash Street Yoga","jsonUsernameLast4":"••••0002","storageSafeLast4":"••••7A01","country":"US","currency":"USD","environment":"test","sharedWithLegacy":false,"verifiedAt":"2026-07-24T12:00:00.000Z","verifyError":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"putTrxAccount","summary":"Write the TRX merchant record and verify its login (platform admins only)","description":"Platform admins on their own session; anyone else is refused. Writes every field (the password only when given), makes the business a TRX business on the first write — 409 when it already has card payments on another provider — derives the currency from the business (USD or CAD; 400 otherwise) and the environment from the gateway URL, then runs an authenticated Credit/Lookup: `00` or `X7` sets `verifiedAt`; a refused login records `verifyError`. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutTrxAccountBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxAccount"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"merchantNumber":"8788290000412","clientId":"412","dba":"Ash Street Yoga","jsonUsernameLast4":"••••0002","storageSafeLast4":"••••7A01","country":"US","currency":"USD","environment":"test","sharedWithLegacy":false,"verifiedAt":"2026-07-24T12:00:00.000Z","verifyError":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-account/check":{"post":{"operationId":"checkTrxConnection","summary":"Check a merchant's TRX gateway login and find TRX's record of it (platform admins only)","description":"Settings › Admin › TRX connection (build-plan/253). Platform admins on their own session. The username must be gateway-shaped (`001433_000002` names client 1433); the login is checked on the checkout gateway (a refused one is 400 on `password`); TRX's record of the client is found with PlaceFull's agent login — the business's own lead, else the agent's boarded leads under the business's name — or `merchant` is null. Nothing is stored: the PUT above connects it. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}},"required":["username","password"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"client":{"type":"string"},"environment":{"type":"string","enum":["test","live"]},"merchant":{"anyOf":[{"type":"object","properties":{"leadGuid":{"type":"string"},"client":{"type":"string"},"dba":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalName":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"owner":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["leadGuid","client","dba","legalName","address","phone","owner","status"],"additionalProperties":false},{"type":"null"}]}},"required":["client","environment","merchant"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-account/verify":{"post":{"operationId":"verifyTrxAccount","summary":"Re-run the login probe on the stored TRX merchant record","description":"Re-run the login probe on the stored TRX merchant record Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxAccount"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"merchantNumber":"8788290000412","clientId":"412","dba":"Ash Street Yoga","jsonUsernameLast4":"••••0002","storageSafeLast4":"••••7A01","country":"US","currency":"USD","environment":"test","sharedWithLegacy":false,"verifiedAt":"2026-07-24T12:00:00.000Z","verifyError":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/trx-account/legacy-pull":{"get":{"operationId":"getLegacyTrxPull","summary":"The last pull of a legacy TRX record asked for on this business — or null (platform admins only)","description":"The last pull of a legacy TRX record asked for on this business — or null (platform admins only) Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/LegacyTrxPull"},{"type":"null"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"requestLegacyTrxPull","summary":"Take the TRX merchant record from the studio's legacy PlaceFull account (platform admins only)","description":"For a business made by hand whose studio already has a TRX merchant account on legacy PlaceFull. Platform admins on their own session; anyone else is refused. Only the processing record crosses — no catalog, no bookings, no link to the legacy account. The ask is a task: the worker, which alone reads legacy, finds the account, and when it is TRX-enabled with a gateway login writes the record exactly as `PUT …/payments/trx-account` would (sealed password, provider `trx`, the verify probe). Asking again replaces an ask that has not started. Poll the GET for the outcome; a record already as legacy has it answers `unchanged`. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegacyTrxPullBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LegacyTrxPull"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments":{"post":{"operationId":"createPayment","summary":"Create a payment","description":"Records a new payment intent against a booking, membership, or customer. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Payment"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/{paymentId}":{"get":{"operationId":"getPayment","summary":"Get a payment","description":"Returns payment status and provider references. Requires feature `business.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PaymentIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Payment"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/{paymentId}/authorize":{"post":{"operationId":"authorizePayment","summary":"Authorize a payment","description":"Authorizes a Stripe payment for later capture. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PaymentIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentActionResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"payment":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"clientSecret":"pi_example_client_secret"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/{paymentId}/capture":{"post":{"operationId":"capturePayment","summary":"Capture an authorized payment","description":"Captures a previously authorized payment. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PaymentIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentActionResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"payment":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"clientSecret":"pi_example_client_secret"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/{paymentId}/refund":{"post":{"operationId":"refundPayment","summary":"Refund a payment","description":"Refunds all or part of a captured payment. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PaymentIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundPaymentBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentActionResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"payment":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"clientSecret":"pi_example_client_secret"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/{paymentId}/receipt":{"post":{"operationId":"resendPaymentReceipt","summary":"Send a payment's receipt again","description":"Sends the payment's own receipt again (QA F25): a card cart's order receipt, a saved-card charge's (balance collected, add-on) booking charge receipt, or a pass's purchase receipt — to `email` when given, else the customer's address. Each call is its own send (never deduped against the automatic receipt), at most 5 per payment an hour (429 past that). 409 `no_receipt` for a demo, $0, manual or paid-elsewhere payment, a membership renewal or a direct booking payment; 409 `no_recipient` when no address is known. Logs `payment.receipt_resent` (the booking's activity when the payment has one) with the address masked. Requires feature `booking.checkin`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PaymentIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"description":"One address; omit to send to the customer's email.","anyOf":[{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"sent":{"type":"boolean"},"kind":{"type":"string","enum":["order_receipt","balance_receipt","membership_receipt"]},"toMasked":{"type":"string"},"skipped":{"type":"string"}},"required":["sent","kind","toMasked"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"sent":true,"kind":"order_receipt","toMasked":"j***@example.com"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/balance":{"get":{"operationId":"getBusinessBalance","summary":"Get business ledger balance","description":"Returns the business's net ledger position — every kind summed, so the platform's application fee is already netted out. Not gross collected. Requires feature `business.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerBalances"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"total":12500,"currency":"USD"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/balance":{"get":{"operationId":"getBookingBalance","summary":"Get booking ledger balance","description":"Returns what the customer has paid on a booking — charge/refund/adjustment only, excluding platform fee rows. Requires feature `booking.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerBalances"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"total":12500,"currency":"USD"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/balance":{"get":{"operationId":"getCustomerBalance","summary":"Get customer ledger balance","description":"Returns what a customer has paid at a business — charge/refund/adjustment only, excluding platform fee rows. Requires feature `crm.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerBalances"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"total":12500,"currency":"USD"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/platform-fee-revenue":{"get":{"operationId":"getPlatformFeeRevenue","summary":"Get platform fee revenue for a business","description":"Returns platform application-fee revenue for a business. Requires feature `business.manage`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerBalances"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"total":12500,"currency":"USD"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers":{"get":{"operationId":"listCustomers","summary":"List customers","description":"Searches and paginates CRM customers with derived stats. Requires feature `crm.view`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"tag","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string"}},{"in":"query","name":"marketingConsent","schema":{"type":"boolean"}},{"in":"query","name":"hasAccount","schema":{"type":"boolean"}},{"in":"query","name":"wallet","schema":{"description":"`true`: only customers holding a Wallet pass a note reaches (build-plan/262).","type":"boolean"},"description":"`true`: only customers holding a Wallet pass a note reaches (build-plan/262)."},{"in":"query","name":"source","schema":{"type":"string"}},{"in":"query","name":"consentSource","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"type":"string"}},{"in":"query","name":"dir","schema":{"type":"string","enum":["asc","desc"]}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"in":"query","name":"format","schema":{"type":"string","enum":["csv","json"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerListResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"customers":[{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"noShowForecast":null,"guardian":null,"dependents":[]}],"total":1,"limit":25,"offset":0,"filterCounts":{"all":1,"subscribed":1,"hasAccount":1,"imported":0,"archived":0,"duplicates":0,"wallet":0}},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createCustomer","summary":"Create a customer","description":"Creates a CRM customer from email or phone. Does not create a PlaceFull account. Requires feature `crm.notes`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"noShowForecast":null,"guardian":null,"dependents":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/export":{"get":{"operationId":"exportCustomersCsv","summary":"Export customers as CSV or JSON","description":"Streams every matching row (no cap). format=csv (default) or json (newline-delimited CustomerDetail). Columns: customer_id, person_id, email, display_name, given_name, family_name, phone, status, source, tags, notes, marketing_consent, consent_source, consent_updated_at, has_account, first_seen_at, last_seen_at, last_booking_start_at, next_booking_start_at, bookings_count, canceled_count, no_show_count, lifetime_spend_amount, lifetime_spend_currency, active_memberships, merged_from_ids, created_at. Requires feature `crm.export`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"tag","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string"}},{"in":"query","name":"marketingConsent","schema":{"type":"boolean"}},{"in":"query","name":"hasAccount","schema":{"type":"boolean"}},{"in":"query","name":"wallet","schema":{"description":"`true`: only customers holding a Wallet pass a note reaches (build-plan/262).","type":"boolean"},"description":"`true`: only customers holding a Wallet pass a note reaches (build-plan/262)."},{"in":"query","name":"source","schema":{"type":"string"}},{"in":"query","name":"consentSource","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"type":"string"}},{"in":"query","name":"dir","schema":{"type":"string","enum":["asc","desc"]}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"in":"query","name":"format","schema":{"type":"string","enum":["csv","json"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"string","description":"CSV file contents"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":"id,email,displayName\n550e8400-e29b-41d4-a716-446655440006,alex@example.com,Alex Rivera","v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/import":{"post":{"operationId":"importCustomers","summary":"Import customers","description":"One chunk (up to 500) of a spreadsheet's rows, keyed by customer field. A row matches an existing customer by email, then phone, and only fills its blanks, adds tags, and moves Customer since earlier; otherwise it adds one. Rows without a usable email or phone, or whose email and phone belong to two customers, come back in `skipped` by index. A `consent` value sets marketing email consent (source `import`) but never overrides a choice the customer made. Sends no email or text. Requires feature `crm.notes`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportCustomersBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerImportResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"added":480,"updated":12,"unchanged":5,"skipped":[{"index":41,"reason":"Missing email and phone"}]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}":{"get":{"operationId":"getCustomer","summary":"Get a customer","description":"Returns a customer with business-owned contact, optional person, and lifetime stats. Requires feature `crm.view`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"noShowForecast":null,"guardian":null,"dependents":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateCustomer","summary":"Update a customer","description":"Updates contact, tags, notes, or marketing consent on a customer. Requires feature `crm.notes`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"noShowForecast":null,"guardian":null,"dependents":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/answers":{"get":{"operationId":"getCustomerLastAnswers","summary":"A customer's last answer to each question","description":"The desk's Last time (architecture/16 § Asked at the desk): for each question named in `questionIds` (comma-separated), the newest answer this customer gave that is still answerable today. Offered beside the field, never filled in. Questions never answered are left out. Requires feature `crm.view`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"},{"in":"query","name":"questionIds","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"questionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"],"additionalProperties":false}]},"lastAnsweredAt":{"type":"string"}},"required":["questionId","value","lastAnsweredAt"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/bookings":{"get":{"operationId":"listCustomerBookings","summary":"List a customer's recent bookings","description":"Last ten bookings for this customer across every location, newest first. The customer drawer uses this so a twelve-booking customer never reads “No bookings yet.” Requires feature `crm.view`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"bookings":{"type":"array","items":{"$ref":"#/components/schemas/OperatorBooking"}}},"required":["bookings"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/purchases":{"get":{"operationId":"listCustomerPurchases","summary":"List a customer's product purchases","description":"Paid product lines for this customer, newest first. The customer record Purchases panel. Requires feature `crm.view`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"},{"in":"query","name":"limit","schema":{"type":"integer","exclusiveMinimum":0,"maximum":200}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"purchases":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"productName":{"type":"string"},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amountTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"status":{"type":"string","enum":["paid","picked_up","canceled"]},"bookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"createdAt":{"type":"string"},"fulfilledAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","productName","variantName","quantity","amountTotal","currency","status","bookingId","createdAt","fulfilledAt"],"additionalProperties":false}}},"required":["total","purchases"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/archive":{"post":{"operationId":"archiveCustomer","summary":"Archive a customer","description":"Soft-archives a CRM customer. Requires feature `crm.notes`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Customer"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/duplicates":{"get":{"operationId":"listCustomerDuplicates","summary":"List possible duplicate customers","description":"Computed possible-duplicate pairs at this business — same normalized name, or the same email local-part on different domains, plus contact-collision events. Requires feature `crm.view`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"pairs":{"type":"array","items":{"type":"object","properties":{"a":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","phone"],"additionalProperties":false},"b":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","phone"],"additionalProperties":false},"reason":{"type":"string","enum":["name","email_local","contact_collision"]}},"required":["a","b","reason"],"additionalProperties":false}}},"required":["pairs"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/merge":{"post":{"operationId":"mergeCustomer","summary":"Merge another customer into this one","description":"Merges another customer into this one. Pass dryRun=true for the receipt without writing. Human-only; irreversible. Requires feature `crm.merge`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"},{"in":"query","name":"dryRun","schema":{"type":"boolean"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergeCustomerBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"receipt":{"type":"object","properties":{"intoCustomerId":{"$ref":"#/components/schemas/Uuid"},"fromCustomerId":{"$ref":"#/components/schemas/Uuid"},"keep":{"type":"object","properties":{"email":{"type":"string","enum":["into","from"]},"phone":{"type":"string","enum":["into","from"]},"name":{"type":"string","enum":["into","from"]}},"required":["email","phone","name"],"additionalProperties":false},"contact":{"type":"object","properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"givenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"familyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["email","phone","givenName","familyName","displayName"],"additionalProperties":false},"repointed":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"}},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["intoCustomerId","fromCustomerId","keep","contact","repointed","refusal"],"additionalProperties":false},"survivor":{"$ref":"#/components/schemas/CustomerDetail"}},"required":["receipt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/split":{"post":{"operationId":"splitCustomer","summary":"Split a contact field onto a new customer","description":"Moves the email or phone onto a new customer. The original must hold both contacts. History stays on the original. Requires feature `crm.merge`.","tags":["crm"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SplitCustomerBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"original":{"$ref":"#/components/schemas/CustomerDetail"},"created":{"$ref":"#/components/schemas/CustomerDetail"}},"required":["original","created"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans":{"post":{"operationId":"createMembershipPlan","summary":"Create a membership plan","description":"Creates a membership plan with optional benefits. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMembershipPlanBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipPlan"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listMembershipPlans","summary":"List membership plans","description":"Lists membership plans for a business. Requires feature `business.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MembershipPlan"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/order":{"patch":{"operationId":"reorderMembershipPlans","summary":"Reorder memberships or passes","description":"Sets catalog display order for memberships ('membership') or passes ('pack'). ids must match the live set exactly. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"family":{"type":"string","enum":["membership","pack"]},"ids":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["family","ids"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MembershipPlan"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/{planId}":{"get":{"operationId":"getMembershipPlan","summary":"Get a membership plan","description":"Returns a plan with benefit definitions. Requires feature `business.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipPlan"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateMembershipPlan","summary":"Update a membership plan","description":"Updates a membership plan (benefits replace-all; price locked after first purchase). Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMembershipPlanBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipPlan"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteMembershipPlan","summary":"Delete a draft plan","description":"Deletes a plan that is a draft and that nobody has ever bought — it goes for good. A published or archived plan answers `409 { code: \"not_a_draft\" }`; a draft with a membership ever sold on it answers `409 { code: \"draft_in_use\" }` — archive those instead. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/{planId}/publish":{"post":{"operationId":"publishMembershipPlan","summary":"Publish a membership plan","description":"Publishes a draft membership plan for purchase. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipPlan"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/{planId}/unpublish":{"post":{"operationId":"unpublishMembershipPlan","summary":"Unpublish a membership plan","description":"Returns a published membership plan to draft. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipPlan"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/{planId}/archive":{"post":{"operationId":"archiveMembershipPlan","summary":"Archive a membership plan","description":"Soft-archives a membership plan. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipPlan"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customers/{customerId}/memberships/purchase":{"post":{"operationId":"purchaseMembership","summary":"Purchase a membership for a customer","description":"Purchases a plan for a customer. One-time/manual activates immediately; recurring Stripe returns a Checkout Session URL and creates the membership on webhook. Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseMembershipBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PurchaseMembershipResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"paymentId":"550e8400-e29b-41d4-a716-446655440009","membership":{"id":"550e8400-e29b-41d4-a716-446655440011","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","paymentId":"550e8400-e29b-41d4-a716-446655440009","billingMode":"card","cardId":"550e8400-e29b-41d4-a716-446655440099","periodAnchorAt":"2026-07-24T12:00:00.000Z","periodNumber":1,"cancelAtPeriodEnd":false,"pausedAt":null,"renewalAttempts":0,"lastRenewalPaymentId":"550e8400-e29b-41d4-a716-446655440009","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"creditsGranted":10},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/record-payment":{"post":{"operationId":"recordMembershipPeriodPayment","summary":"Record a membership period as paid through a payment method","description":"With `channelId`, the period was paid through one of the business's paid-elsewhere payment methods (architecture/24 § Closing out): the period advances and credits are granted, no Payment or ledger row is written, and `membership.period_paid` names the method. Cash is not taken: without `channelId` the request is refused `403 cash_not_taken`. Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordMembershipPeriodPaymentBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"membership":{"$ref":"#/components/schemas/Membership"},"creditsGranted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paymentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["membership","creditsGranted","paymentId"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"membership":{"id":"550e8400-e29b-41d4-a716-446655440011","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","paymentId":"550e8400-e29b-41d4-a716-446655440009","billingMode":"card","cardId":"550e8400-e29b-41d4-a716-446655440099","periodAnchorAt":"2026-07-24T12:00:00.000Z","periodNumber":1,"cancelAtPeriodEnd":false,"pausedAt":null,"renewalAttempts":0,"lastRenewalPaymentId":"550e8400-e29b-41d4-a716-446655440009","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"creditsGranted":10,"paymentId":"550e8400-e29b-41d4-a716-446655440009"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships":{"get":{"operationId":"listMemberships","summary":"List memberships for the operator console","description":"Every membership at the business with plan name, holder name/email, status, renewal, billing mode, and credits remaining. The only surface a studio can inspect memberships from (studios have no Stripe dashboard — architecture/05). Requires feature `business.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipListResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/email":{"post":{"operationId":"changeMembershipEmail","summary":"Change the email a pass or membership belongs to","description":"Change the email a pass or membership belongs to Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeBookingEmailBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChangeEmailResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/cancel":{"post":{"operationId":"cancelMembership","summary":"Cancel a membership","description":"At period end by default: the membership runs to its paid period end, nothing more is charged, and the holder is told (build-plan/265 D7). `atPeriodEnd: false` ends it now; a pass with no period end always ends now. Written locally — the clock is ours (architecture/05 § Recurring billing). Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelMembershipBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"},"membership":{"$ref":"#/components/schemas/Membership"}},"required":["ok","membership"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"uncancelMembership","summary":"Keep a membership — take back a cancel at period end","description":"Clears `cancelAtPeriodEnd` on a membership that has not ended yet, so the next renewal runs as before (build-plan/265 D7). 409 when the membership has already ended. Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"},"membership":{"$ref":"#/components/schemas/Membership"}},"required":["ok","membership"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/renew":{"post":{"operationId":"retryMembershipRenewal","summary":"Try the card again on a past-due membership","description":"The desk's one retry (build-plan/265 D11): charges the period's price to the card on file now and settles the period on approval, without waiting for the retry ladder. A money write — declare `membership.renew` at `POST …/money-effects` and echo it; a mismatch is 409 `money_effect_mismatch`. Only a `card` membership that is past due; anything else is 409. Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryMembershipRenewalBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipRenewalOutcome"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/spots/quote":{"post":{"operationId":"quoteSubscriptionSpots","summary":"Quote a change to a subscription's spots","description":"What changing a subscription to `spots` would do (build-plan/280 § Changing spots): an add takes effect now, charged on the card on file for the sessions left in the term, then the new amount at renewal; a removal takes effect at the term's end with no refund; the term is priced again at the new count with today's discount rules. A session that cannot take the added spot is named in `blocked`. Nothing is written. Refuses (409) a subscription that has ended, is past due, paused or ending, and a count outside the listing's fewest and most per booking; 0 is a cancel (`cancel_instead`). Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["spots"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SpotsChangeQuote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/spots":{"post":{"operationId":"changeSubscriptionSpots","summary":"Change a subscription's spots","description":"Makes the change the quote describes (build-plan/280 § Changing spots). An add resizes every upcoming session under the capacity guard, then charges the card on file; a decline puts it all back and answers the processor's words. A money write — declare `membership.change_spots` (with `membershipId` and `spots`) at `POST …/money-effects` and echo it; a mismatch is 409 `money_effect_mismatch`. Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expectedEffect":{}},"required":["spots"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SpotsChangeResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/card-link":{"post":{"operationId":"sendMembershipCardLink","summary":"Email the holder a link to update the card on file","description":"Books the `membership_card_link` email: one button to the membership's update-card page, where the holder saves a new card and a past-due period is tried again at once (build-plan/265 D8, D11). Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MembershipCardLinkResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/pause":{"post":{"operationId":"pauseMembership","summary":"Pause a membership","description":"Stops the clock: no renewal runs while paused, and the time left in the paid period is kept for the resume (build-plan/265 § Pause). Written locally. Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"},"membership":{"$ref":"#/components/schemas/Membership"}},"required":["ok","membership"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/resume":{"post":{"operationId":"resumeMembership","summary":"Resume a paused membership","description":"Starts the clock again: the period anchor moves forward by the pause, the paid time left runs out from now, and the next renewal is booked at its end. Requires feature `booking.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"},"membership":{"$ref":"#/components/schemas/Membership"}},"required":["ok","membership"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pricing/quote":{"post":{"operationId":"quoteListing","summary":"Quote a listing or a product","description":"Computes price, discounts, and credits for an offering and customer. Requires feature `booking.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteListingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingQuote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pricing/access-check":{"get":{"operationId":"checkListingAccess","summary":"Check a customer’s access to an offering","description":"Checks whether a customer membership grants required access keys. Requires feature `booking.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"offeringId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"customerId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccessCheckResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"allowed":true,"requiredKeys":["premium"],"grantedKeys":["premium"],"missingKeys":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/tax-rates":{"get":{"operationId":"listTaxRates","summary":"List active tax rates","description":"Operator-declared sales-tax rates for the business. Archived rates are omitted. Requires feature `business.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxRate"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"replaceTaxRates","summary":"Replace active tax rates","description":"Archives every active rate and creates the submitted set in one transaction — several taxes (GST and PST, a state and a county tax), or an empty list to stop collecting tax. A name is one tax: the same name twice at the same place is refused. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rates":{"type":"array","items":{"type":"object","properties":{"id":{"description":"The rate this entry replaces, when known. Saving replaces every rate; with the id, a renamed tax carries the revenue categories that name it (architecture/31).","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"type":"string"},"ratePpm":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","ratePpm"]}}},"required":["rates"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxRate"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/tax-setup":{"get":{"operationId":"getTaxSetup","summary":"Tax setup for the Payments panel","description":"Locations with jurisdiction labels, active rates, and a proposal (Canadian seeds, US guidance, or a missing-address prompt). Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TaxSetup"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/tax-rates/{id}":{"patch":{"operationId":"updateTaxRate","summary":"Update a tax rate","description":"Update a tax rate Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/TaxRateIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"ratePpm":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TaxRate"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/tax-rates/{id}/archive":{"post":{"operationId":"archiveTaxRate","summary":"Archive a tax rate","description":"Soft-archives the rate. Existing bookings keep their snapshotted tax. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/TaxRateIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TaxRate"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/revenue-categories":{"get":{"operationId":"listRevenueCategories","summary":"List revenue categories","description":"What a sale is in the studio's books and which taxes it carries (architecture/31). A listing, product or plan is assigned one; a class or reservation may split its price across them. Archived categories are omitted. Requires feature `business.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RevenueCategory"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createRevenueCategory","summary":"Create a revenue category","description":"A live name is unique per business. Nothing is assigned to it until a listing, product or plan names it. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Customer-visible — it prints on the receipt. Plain words: Materials, Service."},"taxMode":{"description":"all (default) = every tax the line's location collects · none = no tax · some = the taxes named in taxNames.","type":"string","enum":["all","none","some"]},"taxNames":{"description":"Required when taxMode is some: names of taxes the business collects (Settings → Taxes). Names, not rate ids.","type":"array","items":{"type":"string"}}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RevenueCategory"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/revenue-categories/{id}":{"patch":{"operationId":"updateRevenueCategory","summary":"Update a revenue category","description":"Rename it or change its taxes. Booked prices keep the name and the taxes they were sold with. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/RevenueCategoryIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"taxMode":{"description":"all (default) = every tax the line's location collects · none = no tax · some = the taxes named in taxNames.","type":"string","enum":["all","none","some"]},"taxNames":{"description":"Required when taxMode is some: names of taxes the business collects (Settings → Taxes). Names, not rate ids.","type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RevenueCategory"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/revenue-categories/{id}/archive":{"post":{"operationId":"archiveRevenueCategory","summary":"Archive a revenue category","description":"Refused with 409 while a live listing, product or plan uses it — the message names them. Requires feature `business.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/RevenueCategoryIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RevenueCategory"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customer-lists":{"get":{"operationId":"listCustomerLists","summary":"List customer lists","description":"Saved rules over customers (architecture/32). Each row carries both counts — customers matching the rule, and subscribed (consent floor). Archived lists are omitted. Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerList"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createCustomerList","summary":"Create a customer list","description":"A live name is unique per business. The rule is six optional ANDed facts; consent is never a fact. Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"rule":{"type":"object","properties":{"tag":{"type":"string"},"lastSeen":{"type":"object","properties":{"op":{"type":"string","enum":["within","more_than","never"]},"days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["op"]},"bookings":{"type":"string","enum":["none","1+","3+","10+"]},"holdsPass":{"type":"boolean"},"hasUpcoming":{"type":"boolean"},"source":{"type":"string","enum":["booking","import","manual"]}}}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerList"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customer-lists/preview-counts":{"post":{"operationId":"previewCustomerListCounts","summary":"Preview list counts for a rule","description":"Both figures for an unsaved rule — the list editor as you change a fact. Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rule":{"type":"object","properties":{"tag":{"type":"string"},"lastSeen":{"type":"object","properties":{"op":{"type":"string","enum":["within","more_than","never"]},"days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["op"]},"bookings":{"type":"string","enum":["none","1+","3+","10+"]},"holdsPass":{"type":"boolean"},"hasUpcoming":{"type":"boolean"},"source":{"type":"string","enum":["booking","import","manual"]}}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerListCounts"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customer-lists/{id}":{"get":{"operationId":"getCustomerList","summary":"Get a customer list","description":"Get a customer list Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerListIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerList"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateCustomerList","summary":"Update a customer list","description":"Update a customer list Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerListIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"rule":{"type":"object","properties":{"tag":{"type":"string"},"lastSeen":{"type":"object","properties":{"op":{"type":"string","enum":["within","more_than","never"]},"days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["op"]},"bookings":{"type":"string","enum":["none","1+","3+","10+"]},"holdsPass":{"type":"boolean"},"hasUpcoming":{"type":"boolean"},"source":{"type":"string","enum":["booking","import","manual"]}}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerList"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customer-lists/{id}/archive":{"post":{"operationId":"archiveCustomerList","summary":"Archive a customer list","description":"Archive a customer list Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerListIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerList"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/customer-lists/{id}/counts":{"get":{"operationId":"getCustomerListCounts","summary":"Count customers matching a list","description":"Both figures — customers and subscribed. The consent floor always applies to subscribed. Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CustomerListIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerListCounts"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages":{"get":{"operationId":"listMessages","summary":"List marketing messages","description":"Draft, scheduled, sending, and sent messages (architecture/32). Filter with `?status=`. Archived messages are omitted. Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"status","schema":{"type":"string","enum":["draft","scheduled","sending","sent"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createMessage","summary":"Create a message draft","description":"Create a message draft Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"locationId":{"$ref":"#/components/schemas/Uuid"},"customerListId":{"$ref":"#/components/schemas/Uuid"},"subject":{"type":"string"},"previewText":{"anyOf":[{"type":"string"},{"type":"null"}]},"bodyMd":{"type":"string"},"buttonLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"buttonUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"wallet":{"description":"Also notify the Wallet passes of the people in the group (build-plan/263).","type":"boolean"}},"required":["name","locationId","customerListId"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}":{"get":{"operationId":"getMessage","summary":"Get a message","description":"Get a message Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateMessage","summary":"Update a message draft","description":"Update a message draft Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"locationId":{"$ref":"#/components/schemas/Uuid"},"customerListId":{"$ref":"#/components/schemas/Uuid"},"subject":{"type":"string"},"previewText":{"anyOf":[{"type":"string"},{"type":"null"}]},"bodyMd":{"type":"string"},"buttonLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"buttonUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"wallet":{"description":"Also notify the Wallet passes of the people in the group (build-plan/263).","type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/schedule":{"post":{"operationId":"scheduleMessage","summary":"Schedule or send a message","description":"draft → scheduled. Omit scheduledAt (or pass null / \"now\") to send as soon as the worker runs. Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"scheduledAt":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/cancel":{"post":{"operationId":"cancelMessage","summary":"Cancel a scheduled message","description":"Cancel a scheduled message Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/reschedule":{"post":{"operationId":"rescheduleMessage","summary":"Reschedule a scheduled message","description":"Reschedule a scheduled message Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"scheduledAt":{"type":"string"}},"required":["scheduledAt"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/clone":{"post":{"operationId":"cloneMessage","summary":"Clone a message into a new draft","description":"Clone a message into a new draft Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/archive":{"post":{"operationId":"archiveMessage","summary":"Archive a message","description":"Archive a message Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/preview":{"get":{"operationId":"previewMessage","summary":"Preview a message as HTML","description":"Preview a message as HTML Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"subject":{"type":"string"},"html":{"type":"string"}},"required":["subject","html"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/recipients":{"get":{"operationId":"listMessageRecipients","summary":"List per-recipient delivery outcomes","description":"Plain-English outcomes for the Sent view (architecture/32). Bounces and complaints first, then clicks and opens. Page with limit + offset. Requires feature `crm.view`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"maximum":9007199254740991}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"outcome":{"type":"string"},"outcomeLabel":{"type":"string"},"at":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"failureDetail":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","customerId","customerName","email","outcome","outcomeLabel","at","failureDetail"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/messages/{id}/test":{"post":{"operationId":"testMessage","summary":"Send a test to the signed-in operator","description":"Send a test to the signed-in operator Requires feature `crm.notes`.","tags":["customers"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MessageIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"sent":{"type":"boolean"}},"required":["sent"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/discounts":{"get":{"operationId":"listDiscounts","summary":"List discounts","description":"Every live discount, active and paused, oldest first, each with its uses and the one sentence it is worded in. Archived discounts are omitted. Requires feature `catalog.manage or booking.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Discount"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createDiscount","summary":"Create a discount","description":"One row: what it applies to (one inclusive list — everything, a category, a listing, a product), the effect (percent, amount each or off the order, set price each), every/gets for BOGO or afterFirst for a threshold (the first N spots pay full price, the rest get it — a sibling discount), the visit's day-and-time window, a minimum that counts what it applies to, an optional code, a run and a use cap, and whether an automatic one is promoted (listed on the listing description; false still applies it). The list is folded (a category retires the listings it covers); a code already in use is refused. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscountDraft"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Discount"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/discounts/{id}":{"get":{"operationId":"getDiscount","summary":"Read a discount","description":"One discount with its uses and description. Requires feature `catalog.manage or booking.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/DiscountIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Discount"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateDiscount","summary":"Update a discount","description":"Any subset of the draft over the row as it stands; the whole is normalized again. `status: paused` takes it out of every quote without losing it. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/DiscountIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"code":{"anyOf":[{"type":"string"},{"type":"null"}]},"appliesTo":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","const":"all"}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","const":"category"},"category":{"type":"string","enum":["class","session","space","product"]}},"required":["kind","category"]},{"type":"object","properties":{"kind":{"type":"string","const":"listing"},"listingId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","listingId"]},{"type":"object","properties":{"kind":{"type":"string","const":"product"},"productId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","productId"]}]}},"effect":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","const":"percent"},"value":{"type":"integer","minimum":1,"maximum":100}},"required":["mode","value"]},{"type":"object","properties":{"mode":{"type":"string","const":"amount"},"value":{"type":"integer","minimum":1,"maximum":9007199254740991},"per":{"type":"string","enum":["unit","order"]}},"required":["mode","value","per"]},{"type":"object","properties":{"mode":{"type":"string","const":"price"},"value":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["mode","value"]}]},"every":{"type":"integer","minimum":1,"maximum":9007199254740991},"gets":{"type":"integer","minimum":1,"maximum":9007199254740991},"afterFirst":{"description":"Which spots get it, as a threshold: the first N spots in the cart pay full price and every spot after that gets the effect — a family's third child at half price. Counted across every line the discount applies to, taken on the cheapest spots. 0 (default) = every spot. Refused together with every > 1 or an amount off the order.","type":"integer","minimum":0,"maximum":9007199254740991},"when":{"anyOf":[{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},"start":{"anyOf":[{"type":"string"},{"type":"null"}]},"end":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["days","start","end"]},{"type":"null"}]},"minQuantity":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"minAmount":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"startsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"endsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"maxUses":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"status":{"type":"string","enum":["active","paused"]},"promote":{"description":"Listed on the listing's description under the price (default true). false = still applies on its own to every cart it fits, but is not listed. Only an automatic discount is listed, so this has no effect on a coded one.","type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Discount"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/discounts/{id}/archive":{"post":{"operationId":"archiveDiscount","summary":"Archive a discount","description":"Retires the discount. Carts already checked out keep the rows their snapshots carry; its code may be reused. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/DiscountIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Discount"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/carts/{token}/code":{"put":{"operationId":"setOperatorCartCode","summary":"Add or remove a staff cart's code","description":"The one code a cart carries (architecture/30). A code is stored only when it applies to the cart as priced now: an unknown, paused, expired or used-up code answers 400 `code` \"That code isn't valid\"; one that wins no line \"That code doesn't apply to anything in this cart\". `null` removes it. 409 while a payment is in flight. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CartTokenParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["code"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PayLinkCart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/calendar-connections":{"get":{"operationId":"getCalendarConnections","summary":"Google Calendar for a person or a location’s spaces","description":"Send `instructorId` for one person’s Team field, or `locationId` for every space at a location. Tokens are never returned. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"instructorId","schema":{"$ref":"#/components/schemas/Uuid"}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"type":"object","properties":{"configured":{"type":"boolean"},"connection":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["active","needs_reauth"]},"email":{"type":"string"},"subject":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","const":"person"},"instructorId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","instructorId"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"space"},"resourceId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","resourceId"],"additionalProperties":false}]},"conflicts":{"type":"array","items":{"type":"object","properties":{"calendarId":{"type":"string"},"name":{"type":"string"},"primary":{"type":"boolean"}},"required":["calendarId","name","primary"],"additionalProperties":false}},"bookings":{"anyOf":[{"type":"object","properties":{"calendarId":{"type":"string"},"name":{"type":"string"}},"required":["calendarId","name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","status","email","subject","conflicts","bookings"],"additionalProperties":false},{"type":"null"}]},"canConnect":{"type":"boolean"},"canDisconnect":{"type":"boolean"}},"required":["configured","connection","canConnect","canDisconnect"],"additionalProperties":false},{"type":"object","properties":{"spaces":{"type":"array","items":{"type":"object","properties":{"configured":{"type":"boolean"},"connection":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["active","needs_reauth"]},"email":{"type":"string"},"subject":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","const":"person"},"instructorId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","instructorId"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"space"},"resourceId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","resourceId"],"additionalProperties":false}]},"conflicts":{"type":"array","items":{"type":"object","properties":{"calendarId":{"type":"string"},"name":{"type":"string"},"primary":{"type":"boolean"}},"required":["calendarId","name","primary"],"additionalProperties":false}},"bookings":{"anyOf":[{"type":"object","properties":{"calendarId":{"type":"string"},"name":{"type":"string"}},"required":["calendarId","name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","status","email","subject","conflicts","bookings"],"additionalProperties":false},{"type":"null"}]},"canConnect":{"type":"boolean"},"canDisconnect":{"type":"boolean"},"resourceId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["configured","connection","canConnect","canDisconnect","resourceId","name"],"additionalProperties":false}}},"required":["spaces"],"additionalProperties":false}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/calendar-connections/start":{"post":{"operationId":"startCalendarConnection","summary":"Start connecting a Google Calendar","description":"Returns Google’s consent URL. The browser comes back to the console, which posts the answer to `/me/google-calendar/complete`. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"instructorId":{"$ref":"#/components/schemas/Uuid"},"resourceId":{"$ref":"#/components/schemas/Uuid"},"returnTo":{"type":"string"}},"required":["returnTo"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"authorizeUrl":{"type":"string"}},"required":["authorizeUrl"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/calendar-connections/{connectionId}/calendars":{"get":{"operationId":"listGoogleCalendars","summary":"The calendars on a Google account","description":"Read live for the connection dialog. Nothing is stored. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CalendarConnectionIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"calendars":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"primary":{"type":"boolean"},"owned":{"type":"boolean"}},"required":["id","name","primary","owned"],"additionalProperties":false}}},"required":["calendars"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/calendar-connections/{connectionId}":{"patch":{"operationId":"updateCalendarConnection","summary":"Save which calendars a connection uses","description":"`conflictCalendarIds` are checked for conflicts. `bookings` is `{ calendarId }`, `{ create: true }` for a new calendar, or null for Don’t add. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CalendarConnectionIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"conflictCalendarIds":{"type":"array","items":{"type":"string"}},"bookings":{"anyOf":[{"type":"object","properties":{"calendarId":{"type":"string"}},"required":["calendarId"]},{"type":"object","properties":{"create":{"type":"boolean","const":true}},"required":["create"]},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["active","needs_reauth"]},"email":{"type":"string"},"subject":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","const":"person"},"instructorId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","instructorId"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"space"},"resourceId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","resourceId"],"additionalProperties":false}]},"conflicts":{"type":"array","items":{"type":"object","properties":{"calendarId":{"type":"string"},"name":{"type":"string"},"primary":{"type":"boolean"}},"required":["calendarId","name","primary"],"additionalProperties":false}},"bookings":{"anyOf":[{"type":"object","properties":{"calendarId":{"type":"string"},"name":{"type":"string"}},"required":["calendarId","name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","status","email","subject","conflicts","bookings"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"disconnectCalendarConnection","summary":"Disconnect a Google Calendar","description":"Disconnect a Google Calendar Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/CalendarConnectionIdParam"}],"responses":{"204":{"description":"No content"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/google-calendar/complete":{"post":{"operationId":"completeCalendarConnection","summary":"Finish connecting a Google Calendar","description":"Google’s answer to the caller’s own Connect. The service requires the session person to be the one who pressed it, and uses the attempt once.","tags":["me"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"redirectTo":{"type":"string"}},"required":["redirectTo"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/calendar/busy":{"get":{"operationId":"getBusinessCalendarBusy","summary":"Google busy time for the calendar’s lanes","description":"Read live after the board, so it never slows it. `from` is included and `to` is exclusive, both `YYYY-MM-DD`. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"from","schema":{"type":"string"},"required":true},{"in":"query","name":"to","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","const":"block"},"id":{"type":"string"},"title":{"type":"string"},"localStart":{"type":"string"},"localEnd":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"endsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"allDay":{"type":"boolean"},"instructorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"spaceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"spaceName":{"anyOf":[{"type":"string"},{"type":"null"}]},"personId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"source":{"type":"string","const":"google"},"googleAccount":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["kind","id","title","localStart","localEnd","startsAt","endsAt","allDay","instructorName","spaceId","spaceName","personId","source","googleAccount"],"additionalProperties":false}}},"required":["events"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/card/preview":{"post":{"operationId":"previewDraftMembershipPlanCard","summary":"Preview an unsaved plan's card","description":"Draws the offer face of a plan that is not saved yet, from its draft fields and a card design, as inline SVG. Nothing is stored. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cardDesign":{"type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","pattern","photo","logo","rationale"],"additionalProperties":false},"plan":{"type":"object","properties":{"name":{"type":"string","minLength":1},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"billingPeriod":{"default":"one_time","type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"expiresAfterDays":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]},"benefits":{"default":[],"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["access","price","credit"]},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type","config"]}},"photoAssetId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["name"]},"width":{"description":"Width in px (default 640).","type":"integer","minimum":56,"maximum":1200},"lighting":{"description":"`live` (the default) leaves out the moving part of the surface's reflection, for the console's light layer to draw; `baked` draws it in, for a still image such as a tile.","type":"string","enum":["baked","live"]}},"required":["cardDesign","plan"]}}}},"responses":{"200":{"description":"The card as SVG","content":{"image/svg+xml":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/{planId}/card/preview":{"post":{"operationId":"previewMembershipPlanCard","summary":"Preview a plan's card","description":"Draws a saved plan's offer face with the given card design, as inline SVG. It never saves: the editor's Save is the write. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cardDesign":{"type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","pattern","photo","logo","rationale"],"additionalProperties":false},"width":{"description":"Width in px (default 640).","type":"integer","minimum":56,"maximum":1200},"lighting":{"description":"`live` (the default) leaves out the moving part of the surface's reflection, for the console's light layer to draw; `baked` draws it in, for a still image such as a tile.","type":"string","enum":["baked","live"]}},"required":["cardDesign"]}}}},"responses":{"200":{"description":"The card as SVG","content":{"image/svg+xml":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/{planId}/card":{"get":{"operationId":"getMembershipPlanCard","summary":"Get a plan's card images","description":"Public URLs of the plan's offer-face card for one slot, rendered on first request and cached by what produced them. Without a width, every cached size of the slot; without a format, WebP for the card and PNG for wallet slots. Requires feature `business.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"},{"in":"query","name":"slot","schema":{"description":"Default `card`","type":"string","enum":["card","strip","thumb","mark","wordmark"]},"description":"Default `card`"},{"in":"query","name":"width","schema":{"description":"One of the slot’s cached widths, in px","type":"string"},"description":"One of the slot’s cached widths, in px"},{"in":"query","name":"format","schema":{"type":"string","enum":["png","webp"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"slot":{"type":"string","enum":["card","strip","thumb","mark","wordmark"]},"renders":{"type":"array","items":{"type":"object","properties":{"hash":{"type":"string","description":"SHA-256 of what produced the render"},"url":{"type":"string","description":"Public, immutable URL of the image"},"storageKey":{"type":"string"},"slot":{"type":"string","enum":["card","strip","thumb","mark","wordmark"]},"width":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"format":{"type":"string","enum":["png","webp"]},"created":{"type":"boolean","description":"False when it was already cached"}},"required":["hash","url","storageKey","slot","width","height","format","created"],"additionalProperties":false}}},"required":["slot","renders"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/memberships/{membershipId}/card.svg":{"get":{"operationId":"getOwnedMembershipCard","summary":"Get a holder's card","description":"The owned face — the plan's card with the holder's facts — as inline SVG, for staff. Drawn per request and never stored. Requires feature `business.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/MembershipIdParam"},{"in":"query","name":"width","schema":{"description":"Width in px (default 640)","type":"string"},"description":"Width in px (default 640)"}],"responses":{"200":{"description":"The owned card as SVG","content":{"image/svg+xml":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/{planId}/card/redesign":{"post":{"operationId":"redesignMembershipPlanCard","summary":"Propose a plan's card design","description":"Proposes a card design (architecture/27-cards.md § Designer). It never saves: the editor's Save is the write. Falls back to the default design when the model is not configured, the call fails, or its proposal fails validation twice. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PlanIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"style":{"description":"A style to design within. It is kept as given and joins `hand_set` in the proposal.","type":"string","enum":["modern","friendly","bold","calm","classic"]},"cardDesign":{"description":"The design in the editor now (architecture/27-cards.md § Spec). Every field its `hand_set` names is fixed, as is every field the stored spec marks hand-set; the model changes the rest.","type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","pattern","photo","logo","rationale"],"additionalProperties":false}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"spec":{"type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","surface","pattern","photo","logo","hand_set","designed_by","rationale"],"additionalProperties":false,"description":"`designed_by` is `ai` for a model design and `default` for the fallback."},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"The AI's one line; logged, never shown in the UI. Null for the default."},"source":{"type":"string","enum":["ai","default"]},"issues":{"description":"What the last proposal failed, when the designer fell back to the default.","type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}},"proposalToken":{"type":"string","description":"Signed, short-lived (30 minutes), bound to this business, this plan (or an unsaved one) and this spec. Send it back as `cardDesignProposal` with the plan create or update whose `cardDesign` is this spec, and the proposal is saved as proposed (`designed_by` stays `ai`)."}},"required":["spec","rationale","source","proposalToken"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/membership-plans/card/redesign":{"post":{"operationId":"redesignDraftMembershipPlanCard","summary":"Propose a card design for an unsaved plan","description":"Proposes a card design (architecture/27-cards.md § Designer). It never saves: the editor's Save is the write. Falls back to the default design when the model is not configured, the call fails, or its proposal fails validation twice. Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"style":{"description":"A style to design within. It is kept as given and joins `hand_set` in the proposal.","type":"string","enum":["modern","friendly","bold","calm","classic"]},"cardDesign":{"description":"The design in the editor now (architecture/27-cards.md § Spec). Every field its `hand_set` names is fixed, as is every field the stored spec marks hand-set; the model changes the rest.","type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","pattern","photo","logo","rationale"],"additionalProperties":false},"name":{"type":"string","minLength":1},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"billingPeriod":{"description":"Omitted means one_time (a pass).","type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"expiresAfterDays":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]},"benefits":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["access","price","credit"]},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type","config"]}}},"required":["name"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"spec":{"type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","surface","pattern","photo","logo","hand_set","designed_by","rationale"],"additionalProperties":false,"description":"`designed_by` is `ai` for a model design and `default` for the fallback."},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"The AI's one line; logged, never shown in the UI. Null for the default."},"source":{"type":"string","enum":["ai","default"]},"issues":{"description":"What the last proposal failed, when the designer fell back to the default.","type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}},"proposalToken":{"type":"string","description":"Signed, short-lived (30 minutes), bound to this business, this plan (or an unsaved one) and this spec. Send it back as `cardDesignProposal` with the plan create or update whose `cardDesign` is this spec, and the proposal is saved as proposed (`designed_by` stays `ai`)."}},"required":["spec","rationale","source","proposalToken"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/app-config":{"get":{"operationId":"getAppConfig","summary":"Public client configuration","description":"Runtime configuration for browser clients: the product name, the environment, and the currency and date-format options the signup form renders. Unauthenticated, because the console needs it before anyone has signed in. The product name is served rather than compiled into the client so that renaming it is a deployment change, not a rebuild.","tags":["system"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AppConfig"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}}}}},"/me/context":{"get":{"operationId":"getMyContext","summary":"Boot context for the signed-in person","description":"Everything a client needs to decide what to render on load: who the caller is, and the businesses they hold an operator role in, each with its locations and the roles held. Businesses are resolved through UserRole, so this never reveals a business the caller has no relationship with. An empty `businesses` array means the person has signed in but has not created a business yet.","tags":["me"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MeContext"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/changes":{"get":{"operationId":"getBusinessChanges","summary":"Console freshness marker","description":"Returns `{ marker }` — the count of `event` rows for the business. Business-scoped and deliberately coarse: answers \"did anything change?\", never \"what changed?\". Not narrowed by location (payment/membership/waitlist/cart events would be silently dropped). Not a cursor; uuid-v7 id order is irrelevant. Requires feature `booking.view`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChangesMarker"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/home":{"get":{"operationId":"getBusinessHome","summary":"Today — the operator console's first tab","description":"Today at one location, always in the location's own timezone — there is no day to ask for. `calendar` is the ops calendar's read for today and the seven days after it (classes, booked rentals and reservations, blocks, cancelled dates), exactly what the Calendar tab shows for those days; each party carries what it owes and who booked it. `needsYou` lists only what an owner must act on: balances due, failed tasks, past-due memberships, bounced confirmation emails, and one row when QuickBooks posting failed. Instructor-scoped operators receive 403 — use my-day instead. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/HomeSummary"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/home/activity":{"get":{"operationId":"getHomeActivity","summary":"Today's Activity — booked, added, cancelled and moved","description":"The location's bookings as they happened, newest first: booked online by a customer, posts that went out (`posted`, one row per post), added by someone on the team (named), cancelled (and by whom, when the team did it), moved (from and to). `seenAt` is when this person last read Activity at this location — anything after it is new to them; null means nothing is. Page with `before` = `next`. Instructor-scoped operators receive 403. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"before","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/HomeActivityPage"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/home/activity/seen":{"post":{"operationId":"markHomeActivitySeen","summary":"Mark Activity read","description":"What happened at the location before `at` (default now) is no longer new to the signed-in person. The marker never moves back. An API key has no person: 204, nothing stored. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"at":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/HomeActivitySeen"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/home/needs-you/dismiss":{"post":{"operationId":"dismissHomeNeedsYou","summary":"Dismiss Needs-you rows","description":"Hides Needs-you rows by their `key` for everyone at the location, until the row's facts change — a new failure, a new amount, a new day is a new key, so the row comes back. Keys not on the board right now are ignored. At most 100 at a time. Instructor-scoped operators receive 403. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"minItems":1,"maxItems":100,"type":"array","items":{"type":"string"}}},"required":["keys"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NeedsYouDismissed"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/readiness":{"get":{"operationId":"getLocationReadiness","summary":"Can a customer book this location, and what is first if not","description":"The setup guide's source of truth (build-plan/133, reordered by 135). `bookable` mirrors the storefront gates exactly — Connect charges enabled, a current merchant agreement, and a published offering with a slot inside its horizon — so it never disagrees with cart creation. `steps` is the guide in order (class, agreement, team): done / now / later, `blocking` when a customer checkout waits on it, and `focusId` / `focusType` naming the offering the action should open. **Payments is deliberately not a step** — a merchant learns the console before connecting Stripe, so finishing every step does not imply `bookable`. `agreement` appears only when the accepted version is stale. `firstBookingAt` is the earliest non-hold booking at the location, any channel. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LocationReadiness"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/occupancy":{"get":{"operationId":"getLocationOccupancy","summary":"Who is at this location right now","description":"Occupancy is a read, not a record (build-plan/180): every seat is already a booking or a claim, so nothing here can drift. `onNow` is everything in progress — classes, reservations, rentals and open rooms — plus one row per walk-in room with nothing on in it. `rooms` pools a room's spots across every start and activity sharing it, exactly as a hold would, so the number here and a booking for right now can never disagree. `here` is checked-in bookings plus door claims, `expected` is booked-but-not-arrived, `walkIns` is the door claims alone. `walkIn` is the projection a public bar renders: `available` is false unless a room sells a published per-person space, the location is open and bookings are not paused. `changesAt` is the next occurrence boundary. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OccupancyNow"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/my-day":{"get":{"operationId":"getMyDay","summary":"Day view of the schedule and roster","description":"Everything booked for one local day with capacity and roster — no money or aggregates. Scoped by the caller's operator scope: instructors see only their own classes and reservations; business-scoped callers see the whole day. Each class carries its room (the date's own, else the listing's) and `here`, the seats checked in. `comingUp` is the same scope's classes over the seven days after `day` (location time), one line each with the count booked, at most 20. Requires feature `booking.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"day","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"day":{"type":"string"},"timezone":{"type":"string"},"sessions":{"type":"array","items":{"type":"object","properties":{"occurrenceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"offeringName":{"type":"string"},"offeringColor":{"type":"string"},"offeringIcon":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"type":"string"},"roomName":{"anyOf":[{"type":"string"},{"type":"null"}]},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"here":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"roster":{"type":"array","items":{"type":"object","properties":{"bookingId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"customerName":{"type":"string"},"customerEmail":{"type":"string"},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string"}},"required":["bookingId","customerName","customerEmail","partySize","status"],"additionalProperties":false}}},"required":["occurrenceId","offeringId","startsAt","endsAt","offeringName","offeringColor","offeringIcon","locationName","roomName","booked","capacity","here","roster"],"additionalProperties":false}},"comingUp":{"type":"array","items":{"type":"object","properties":{"occurrenceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"offeringName":{"type":"string"},"roomName":{"anyOf":[{"type":"string"},{"type":"null"}]},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["occurrenceId","offeringId","offeringName","roomName","startsAt","endsAt","booked","capacity"],"additionalProperties":false}}},"required":["day","timezone","sessions","comingUp"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/calendar":{"get":{"operationId":"getBusinessCalendar","summary":"Ops calendar range for the Calendar tab","description":"Half-open local-date window of projected open hours plus class dates, booked rentals and reservations, and blocked time. `spaces` is rooms at the location; events carry spaceId/spaceName. Draft and hidden classes included; archived excluded. Instructor scope sees only their classes plus hours and blocked time. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"from","schema":{"type":"string"},"required":true},{"in":"query","name":"to","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OpsCalendarSummary"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/calendar/items":{"get":{"operationId":"getBusinessCalendarItems","summary":"Posts and scheduled messages on the Calendar’s days","description":"Local days `from` through `to`, both included (at most 62). `posts`: the location’s posts whose earliest target falls in them, at that time, with status (`scheduled` while any target waits, `posted`, `failed`, or `partial`, naming the networks that failed) and what their links brought; a canceled post is left out unless some of it went out. `sends`: the journey’s automatic Confirmation, Reminder and Message rows still pending, grouped by step, due minute and channel, counted. Requires feature `location.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"from","schema":{"type":"string"},"required":true},{"in":"query","name":"to","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"title":{"type":"string"},"line":{"type":"string"},"kind":{"type":"string","enum":["occurrence","listing","series","week","plan"]},"networks":{"type":"array","items":{"type":"string","enum":["instagram","facebook"]}},"at":{"type":"string"},"status":{"type":"string","enum":["scheduled","posted","partial","failed"]},"failed":{"type":"array","items":{"type":"string","enum":["instagram","facebook"]}},"clicks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidLabel":{"type":"string"}},"required":["id","title","line","kind","networks","at","status","clicks","booked","paidMinor","paidLabel"],"additionalProperties":false}},"sends":{"type":"array","items":{"type":"object","properties":{"stepId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"stepName":{"type":"string"},"journeyName":{"type":"string"},"channel":{"type":"string","enum":["email","sms"]},"at":{"type":"string"},"emails":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"texts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["stepId","stepName","journeyName","channel","at","emails","texts"],"additionalProperties":false}}},"required":["posts","sends"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/journey-sends":{"get":{"operationId":"listJourneySends","summary":"One day’s scheduled messages, with each recipient","description":"The `sends` groups of one local day, each with its recipients (pending, and those skipped today) and its words as they will go to the first: the email’s subject and text, or the text message. Skip one with the booking step’s skip. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"day","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"groups":{"type":"array","items":{"type":"object","properties":{"stepId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"stepName":{"type":"string"},"journeyName":{"type":"string"},"channel":{"type":"string","enum":["email","sms"]},"at":{"type":"string"},"preview":{"type":"object","properties":{"subject":{"type":"string"},"text":{"type":"string"}},"required":["text"],"additionalProperties":false},"recipients":{"type":"array","items":{"type":"object","properties":{"bookingStepId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"bookingId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"customerName":{"type":"string"},"listingName":{"type":"string"},"channel":{"type":"string","enum":["email","sms"]},"status":{"type":"string","enum":["pending","skipped"]}},"required":["bookingStepId","bookingId","customerName","listingName","channel","status"],"additionalProperties":false}}},"required":["stepId","stepName","journeyName","channel","at","preview","recipients"],"additionalProperties":false}}},"required":["groups"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/chat-llm":{"get":{"operationId":"getChatLlm","summary":"List chat model providers","description":"What the signed-in console can send as `provider` / `model` on a chat turn. `switchable` is true only when APP_ENV is not production. Model names only — the Ollama URL never leaves the server.","tags":["chat"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"switchable":{"type":"boolean"},"provider":{"type":"string","enum":["anthropic","ollama"]},"model":{"type":"string"},"providers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["anthropic","ollama"]},"label":{"type":"string"},"configured":{"type":"boolean"},"models":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"tools":{"type":"boolean"}},"required":["name","tools"],"additionalProperties":false}}},"required":["id","label","configured","models"],"additionalProperties":false}}},"required":["switchable","provider","model","providers"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/chat":{"post":{"operationId":"postChat","summary":"Ask: send a message","description":"Starts or continues a conversation and streams the reply as Server-Sent Events. Tools run in-process against the same services REST uses. A tool marked `destructive` is not executed — the stream emits a `proposal` event and stops, and the caller must confirm it explicitly. Responds with `text/event-stream`. Requires feature `booking.view`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"session_id":{"type":"string"},"message":{"type":"string"},"ui_context":{"$ref":"#/components/schemas/ChatUiContext"},"provider":{"type":"string","enum":["anthropic","ollama"]},"model":{"type":"string","maxLength":120}},"required":["message"]}}}},"responses":{"200":{"description":"SSE stream","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatStreamNote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/setup-chat":{"post":{"operationId":"postSetupChat","summary":"Ask (setup): send a message","description":"The guided first conversation (build-plan/137): the same agent loop as the operator chat, scoped to the signed-in person rather than a business, because it runs before one exists. A session starts unscoped and Go live binds it to the new business; from then on setup is closed (MDH-53) — a turn on a bound session is a 409, and everything after Go live is the console’s Ask. Responds with `text/event-stream`.","tags":["chat"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"session_id":{"type":"string"},"message":{"type":"string"},"provider":{"type":"string","enum":["anthropic","ollama"]},"model":{"type":"string","maxLength":120}},"required":["message"]}}}},"responses":{"200":{"description":"SSE stream","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatStreamNote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"getLatestSetupChat","summary":"Resume the latest setup conversation","description":"The open setup session — one that has not gone live yet — with its transcript and the local plan (build-plan/140). Empty when they have not started, or once their setup went live: a business’s setup is never reopened (MDH-53).","tags":["chat"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SetupChatResume"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"patchSetupDraft","summary":"Type the setup answers","description":"The typed path (MDH-52): the setup dialog’s Business name, What you sell and Your name fields, written straight onto the draft — the same draft, through the same service, as Ask (setup)’s `set_setup_draft`. Needs no chat turn: with no `session_id` it writes to the setup already open, or starts one. A blank or null value clears that fact. `sells` is module keys; a chosen kind counts toward Go live on its own. `ownerTeaches` is \"Do you teach these?\" (MDH-53): true makes the owner the instructor of the classes Go live writes. `sellInStore` is \"Sell these in store?\" (MDH-108), asked once while the plan holds products from the site’s shop: true lists them in the shop and puts every priced one on sale at Go live; false or unanswered writes them as drafts. 409 once the session has gone live.","tags":["chat"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"session_id":{"type":"string"},"name":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"sells":{"type":"array","items":{"type":"string","enum":["classes","sessions","spaces","memberships"]}},"ownerName":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"ownerTeaches":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"sellInStore":{"anyOf":[{"type":"boolean"},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SetupDraftPatchResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/setup-chat/{sessionId}/confirm":{"post":{"operationId":"postSetupChatConfirm","summary":"Confirm a setup proposal","description":"Executes a proposal Ask (setup) emitted — creating the business is one — and resumes the stream. Responds with `text/event-stream`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/SessionIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"proposal_id":{"type":"string"},"provider":{"type":"string","enum":["anthropic","ollama"]},"model":{"type":"string","maxLength":120}},"required":["proposal_id"]}}}},"responses":{"200":{"description":"SSE stream","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatStreamNote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/setup-chat/{sessionId}/preview":{"post":{"operationId":"postSetupPreview","summary":"Ask (setup): render the page being built","description":"The real location page, rendered from what the agent has recorded so far. Before the business exists it renders from the draft alone; after, it is the real page with the draft layered on. HTML, for an iframe `srcdoc`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/SessionIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SetupPreviewHtml"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/setup-chat/{sessionId}":{"get":{"operationId":"getSetupDraft","summary":"Ask (setup): read the draft","description":"What Ask (setup) has recorded, including a pending website find the operator has not applied yet (build-plan/137).","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/SessionIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SetupDraftView"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/setup-chat/{sessionId}/commit":{"post":{"operationId":"postSetupCommit","summary":"Go live from the setup draft","description":"The Go live pill (MDH-52): creates the business and writes the plan in one post, from the draft alone — no model turn, so setup completes with the assistant down. The same commit the agent’s `commit_setup` makes. Blockers refuse the write; rows left hidden come back in `hidden`, one sentence per fix. Pressing Go live accepts the Merchant Agreement. 409 once the business exists.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/SessionIdParam"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SetupCommitResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/setup-chat/{sessionId}/apply-site":{"post":{"operationId":"postSetupApplySite","summary":"Apply the website find to the setup page","description":"Puts the last `preview_setup_site` find onto the draft — name, address, logo, colour — or marks it skipped. The page preview re-renders from the result.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/SessionIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"skip":{"type":"boolean"},"logoUrl":{"type":"string"},"ctaColor":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SetupApplySiteResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/chat/{sessionId}/confirm":{"post":{"operationId":"postChatConfirm","summary":"Confirm a proposed destructive action","description":"Executes a proposal previously emitted by the agent and resumes the stream. Proposals are single-use and expire after ten minutes. Responds with `text/event-stream`. Requires feature `booking.view`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SessionIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"proposal_id":{"type":"string"},"ui_context":{"$ref":"#/components/schemas/ChatUiContext"},"provider":{"type":"string","enum":["anthropic","ollama"]},"model":{"type":"string","maxLength":120}},"required":["proposal_id"]}}}},"responses":{"200":{"description":"SSE stream","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatStreamNote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/chat/{sessionId}/decline":{"post":{"operationId":"postChatDecline","summary":"Decline a proposed destructive action","description":"Answers a proposal with no — one by `proposal_id`, or every open one on the session when it is absent. The refusal is recorded as a tool result the agent reads. The stream resumes only when this answered the last open proposal of a turn that also had one confirmed. Responds with `text/event-stream`. Requires feature `booking.view`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SessionIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"proposal_id":{"type":"string"},"ui_context":{"$ref":"#/components/schemas/ChatUiContext"},"provider":{"type":"string","enum":["anthropic","ollama"]},"model":{"type":"string","maxLength":120}}}}}},"responses":{"200":{"description":"SSE stream","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatStreamNote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/chat/sessions":{"get":{"operationId":"listChatSessions","summary":"List chat sessions","description":"Conversations the caller has had with this business, most recently updated first. Scoped to the caller — another person's session is not listed. Requires feature `booking.view`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ChatSession"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/chat/sessions/{sessionId}":{"get":{"operationId":"getChatSession","summary":"Get a chat transcript","description":"The full message history for one session, as stored rows (`messages`) and as a surface draws it (`turns`: text, photos and one tool_end frame per finished call; `pendingProposals`: the cards still waiting on an answer). A session belonging to another person or business returns 404 rather than 403, so the response never confirms it exists. Requires feature `booking.view`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SessionIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"session":{"$ref":"#/components/schemas/ChatSession"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"turns":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant"]},"blocks":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","const":"text"},"text":{"type":"string"},"images":{"type":"array","items":{"type":"string"}}},"required":["kind","text"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"tool"},"frame":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["kind","frame"],"additionalProperties":false}]}}},"required":["role","blocks"],"additionalProperties":false}},"pendingProposals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"summary":{"type":"string"},"toolName":{"type":"string"}},"required":["id","summary","toolName"],"additionalProperties":false}}},"required":["session","messages","turns","pendingProposals"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"archiveChatSession","summary":"Archive a chat session","description":"Soft-archives the conversation. The transcript is retained — \"what did the agent do to this business?\" has to stay answerable. Requires feature `booking.view`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SessionIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatSession"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/listing":{"post":{"operationId":"proposeListingInline","summary":"Propose offering form values from plain English","description":"Inline AI for the class and reservation editors: turns a sentence into field patches and, for a class, optional schedule drafts. Does not write — the console confirms and fills the form. Proposals are HMAC-signed and expire after ten minutes. `offeringType` shapes what may be proposed: a `session` has no schedules and no capacity (its starts come from each instructor's bookable hours), and carries `durationMinutes` instead. Requires feature `catalog.manage`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"offeringType":{"type":"string","enum":["class","session"]},"current":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"instructors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"email":{"type":"string"}},"required":["id","name","email"]}},"reviseText":{"type":"string"},"transcript":{"type":"array","items":{"$ref":"#/components/schemas/InlineTranscriptTurn"}},"stagedSchedules":{"type":"array","items":{"$ref":"#/components/schemas/InlineScheduleDraft"}},"missingRequired":{"type":"array","items":{"type":"string"}}},"required":["text","locationId"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InlineListingProposal"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/plan":{"post":{"operationId":"proposePlanInline","summary":"Propose membership or pass form values from plain English","description":"Inline AI for the membership and pass editors: turns a sentence into name, price, description, billing, and benefit hints. Does not write — the console confirms and fills the form. `planSurface` shapes what may be proposed: a pass is a one-time credit bundle; a membership is recurring access. Proposals are HMAC-signed and expire after ten minutes. Requires feature `catalog.manage`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"planSurface":{"type":"string","enum":["membership","pack"]},"current":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"reviseText":{"type":"string"},"transcript":{"type":"array","items":{"$ref":"#/components/schemas/InlineTranscriptTurn"}},"missingRequired":{"type":"array","items":{"type":"string"}}},"required":["text"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InlinePlanProposal"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/embed-css":{"post":{"operationId":"proposeEmbedCssInline","summary":"Propose a revised embed stylesheet from plain English","description":"Customize’s assistant (build-plan/273): the CSS in the editor and a sentence in, the whole revised stylesheet for the location’s plain embed tags and one short reply out. One model call, given the embed contract’s markup and themes, the live markup for the `view` on screen, the base the tag wears (and on `studio`, the Look’s values) and the sheet as it stands. The answer is linted as Save lints it; a refused answer is retried once, and a second refusal returns `css: null` with the reply and the refusals. Does not write — the console puts the sheet in the editor, and Save is the owner’s. Requires feature `location.manage`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"css":{"type":"string"},"message":{"type":"string"},"transcript":{"type":"array","items":{"$ref":"#/components/schemas/InlineTranscriptTurn"}},"view":{"type":"string","enum":["schedule","classes","appointments","rentals","times","walkins"]},"listing":{"type":"string"},"theme":{"type":"string","enum":["clean","studio"]}},"required":["locationId","css","message","view","theme"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InlineEmbedCssProposal"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/format-text":{"post":{"operationId":"formatMarkdownInline","summary":"Clean up the formatting of a document","description":"One pass over text the operator already wrote: headings, lists and bold, with the words left as they are. Does not write — the console replaces the field, and Save is still the operator’s. A pass that rewrites the words is refused. Requires feature `location.manage, business.manage, team.manage, or booking.manage`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FormattedMarkdown"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/listing-mark":{"post":{"operationId":"pickListingMarkInline","summary":"Pick a listing’s icon and colour from its name","description":"The mark a listing of this name should wear on the calendar: the picker icon whose meaning fits the name (a holiday first, then who it is for, then what they make) and a swatch no live listing at the location wears — the one worn by the fewest once all twelve are. One model call; when the model cannot answer, the rule half still does (`source: rule`): no icon and the least-worn swatch. Does not write — the console fills How it shows on a new listing while it is named, a hand pick wins, and Save is the operator’s. Requires feature `catalog.manage`.","tags":["chat"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"The listing’s name as typed so far."},"kind":{"description":"class, party, rental or appointment; class when omitted.","type":"string","enum":["class","party","rental","appointment","block"]},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"listingId":{"description":"The listing itself, left out of the marks in use.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["name","locationId"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingMarkPick"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/rewrite-text":{"post":{"operationId":"rewriteTextInline","summary":"Write a description in the business’s voice","description":"One pass over a description the operator started: rewrite, shorter or longer, in the voice of the business’s other descriptions, keeping every fact and inventing none. With `listing`, it is a listing’s description: the listing guide applies, the saved listing’s page details are read so the words need not repeat them, and empty `text` with a name writes a first draft from the name. Does not write — the console replaces the field, Undo puts the words back, and Save is still the operator’s. Requires feature `catalog.manage, location.manage, business.manage, team.manage, or booking.manage`.","tags":["chat"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"mode":{"type":"string","enum":["rewrite","shorter","longer"]},"field":{"description":"The field’s label — Description, What to bring.","type":"string","maxLength":80},"subject":{"description":"What it describes — class, appointment, team member.","type":"string","maxLength":80},"listing":{"description":"Set on a listing’s description: the listing guide, its details, and a draft from its name.","type":"object","properties":{"id":{"description":"The saved listing; null while it is new.","anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"name":{"description":"The name as typed, saved or not.","anyOf":[{"type":"string"},{"type":"null"}]}}}},"required":["text"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RewrittenMarkdown"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/health":{"get":{"operationId":"getHealth","summary":"Health check","description":"Confirms the API process is up and Postgres is reachable.","tags":["system"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/HealthReport"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"status":"ok","db":"up","uptimeSeconds":3600,"timestamp":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}}}}},"/health/worker":{"get":{"operationId":"getWorkerHealth","summary":"Worker health check","description":"Confirms the background worker is keeping up: 503 `service_unavailable` once a due task has waited ten minutes unclaimed, with the count and the oldest wait in `details`. Answering at all proves the API and Postgres too, so an uptime monitor needs only this one.","tags":["system"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WorkerHealthReport"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"status":"ok","worker":"up","overdueTasks":0,"oldestOverdueSeconds":null,"timestamp":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}}}}},"/auth/challenges":{"post":{"operationId":"requestAuthChallenge","summary":"Request a passwordless verification challenge","description":"Starts passwordless login by emailing or texting a verification code. While sign-up is invite-only, an email with no account gets a code only with the pilot `invite` — otherwise the same 201 answer and nothing is sent, so the endpoint never says which emails have accounts. Limited per email and per client address; an email that has spent its daily budget of wrong codes is refused for an hour (429).","tags":["auth"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestChallengeBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RequestChallengeResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"challengeId":"550e8400-e29b-41d4-a716-446655440017","channel":"email_code","expiresAt":"2026-08-01T18:00:00.000Z"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/auth/verify":{"post":{"operationId":"verifyAuthChallenge","summary":"Verify a challenge and receive a session token","description":"Exchanges a verification code for a session bearer token and person record.","tags":["auth"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyChallengeBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VerifyChallengeResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"sessionToken":"sess_example_token_not_a_real_secret","sessionExpiresAt":"2026-08-01T18:00:00.000Z","person":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"claimed":[{"businessName":"River Studio"}]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"verifyAuthChallengeGet","summary":"Open a magic link: a page that posts it back to verify","description":"Consumes nothing. Renders a page that posts `challengeId`, `token` and `redirectTo` to `POST /auth/verify` as a form — by itself where scripts run, with a Continue button where they do not — so a mail scanner that fetches the link spends nothing. The form post consumes the challenge, writes the session key for the landing surface (`admin.session` under `/app`, otherwise `sf_session`), and redirects by same-origin `redirectTo`, else last surface, else `/app/`.","tags":["auth"],"parameters":[{"in":"query","name":"challengeId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"token","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"HTML page that posts the link to POST /auth/verify","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/auth/me":{"get":{"operationId":"getAuthMe","summary":"Get the authenticated person (auth namespace)","description":"Returns the person linked to the current session (auth namespace alias).","tags":["auth"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/auth/sign-out":{"post":{"operationId":"signOut","summary":"Revoke the current session","description":"Sessions are long-lived and rolling (architecture/16 § member sign-in), so sign-out is a real server-side revoke — the shared-device escape hatch — not just a client forgetting its token.","tags":["auth"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignOutResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/auth/sign-out-all":{"post":{"operationId":"signOutAll","summary":"Revoke every session the signed-in person holds","description":"Sign out everywhere: every browser and terminal session of this person, the calling one included. For a lost device or a token that may have leaked. Session bearer only; OAuth connections are not sessions and stay.","tags":["auth"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignOutResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/persons/{id}":{"get":{"operationId":"getPerson","summary":"Get a person","description":"Fetches a person by ID.","tags":["person"],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updatePerson","summary":"Update a person","description":"Updates profile fields on a person record.","tags":["person"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePersonBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations":{"get":{"operationId":"listLocations","summary":"List locations for a business","description":"Lists all locations belonging to a business.","tags":["location"],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Location"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createLocation","summary":"Create a location","description":"Adds a new location under a business. Requires feature `location.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLocationBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Location"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}":{"get":{"operationId":"getLocation","summary":"Get a location","description":"Returns a location by ID.","tags":["location"],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Location"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateLocation","summary":"Update a location","description":"Updates location address, timezone, contact details, links, default class length, default reservation length, page theme, booking pause, or the CSS for its plain embed tags. `links` and `embedCss` each replace the whole value. Requires feature `location.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLocationBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Location"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/archive":{"post":{"operationId":"archiveLocation","summary":"Archive a location","description":"Soft-archives a location. Requires feature `location.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Location"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/slug":{"patch":{"operationId":"updateLocationSlug","summary":"Override a location slug","description":"Override a location slug Requires feature `location.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"}},"required":["slug"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Location"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/slug/revert":{"post":{"operationId":"revertLocationSlug","summary":"Revert a location slug to auto-generated from the current name","description":"Revert a location slug to auto-generated from the current name Requires feature `location.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Location"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/closures":{"get":{"operationId":"listClosures","summary":"List a location's upcoming blocked time","description":"Blocked time a location observes — its own plus any business-wide rows. Negative time that subtracts from availability (a holiday, a one-off closed day). Only rows ending in the future, soonest first. Requires feature `location.view`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Closure"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createClosure","summary":"Block time or add a holiday","description":"Adds negative time to a location. An **all-day** block is a `date` (optionally through `endDate`, inclusive) in the location timezone; a **timed** block passes explicit UTC `startsAt`/`endsAt` for a partial-day close. `annual: true` (all-day only) writes several years of rows sharing a `seriesId`. `resourceId` scopes the block to one room, so a floor refinish closes the Loft and leaves the rest of the studio bookable; omit it to close the whole location. A window with booked dates inside it (classes, reservations, rentals — in the named room when there is one; every year of an annual holiday) answers `409 { code: \"stranded_dates\", dates }` and writes nothing until `strandedDates` says `keep` or `cancel` (build-plan/166). The response carries `affectedBookings`, the same count. Requires feature `location.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"annual":{"type":"boolean"},"resourceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"strandedDates":{"$ref":"#/components/schemas/StrandedDecision"}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Closure"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/closures/holiday-suggestions":{"get":{"operationId":"listHolidaySuggestions","summary":"US federal holidays for the location year","description":"A starter list for the blocked-time editor — US federal holidays computed for the location's current year. Suggestions only; the operator accepts the ones the studio actually closes for. Requires feature `location.view`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HolidaySuggestion"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/calendar-feeds":{"get":{"operationId":"listCalendarFeeds","summary":"List subscribe calendars for a location","description":"Operator calendar feeds for this location (studio, per-space, and the caller’s own classes). Returns panel context — whether there is anything to put on a calendar, whether the caller teaches here, and the spaces that can have their own feed. `teaching` feed URLs are only returned to that person. See architecture/23-operator-calendars.md. Requires feature `location.view`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CalendarFeedsPayload"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createCalendarFeed","summary":"Create a subscribe calendar","description":"Mints a secret subscribe URL for this location. `studio` and `space` need location.manage. `teaching` is allowed when the signed-in person teaches here. The token is a password — anyone with the URL sees class names and times, not customer details. Requires feature `location.view`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/PersonIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["studio","space","teaching"]},"resourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["kind"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CalendarFeed"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/calendar-feeds/{feedId}/rotate":{"post":{"operationId":"rotateCalendarFeed","summary":"Replace a subscribe calendar link","description":"Issues a new token. The old URL 404s immediately. Add the calendar again in Google or Apple. Requires feature `location.view`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"id","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"path","name":"feedId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CalendarFeedRotated"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/calendar-feeds/{feedId}/revoke":{"post":{"operationId":"revokeCalendarFeed","summary":"Stop a subscribe calendar","description":"The link stops working. Google and Apple keep showing old classes until the owner removes the calendar there. Requires feature `location.view`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"id","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"path","name":"feedId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/closures/{closureId}":{"delete":{"operationId":"deleteClosure","summary":"Remove blocked time","description":"Removes blocked time. Deleting any row of an annual holiday removes the whole series. Does not cancel bookings that were already made — it only reopens availability. Requires feature `location.manage`.","tags":["location"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"closureId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/resources":{"post":{"operationId":"createResource","summary":"Create a space","description":"Creates a bookable space (room, equipment, etc.) at a location. Capacity is an ordered list of positions; names are optional. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateResourceBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Resource"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440007","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","kind":"room","name":"Studio A","description":"Heated room with mirrors","capacity":20,"positionLayout":"list","hoursByDay":{"sat":{"start":"11:00","end":null},"sun":{"closed":true}},"seating":"door","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"imageUrl":null,"positions":[{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":0,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":1,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":2,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":3,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":4,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":5,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":6,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":7,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":8,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":9,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":10,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":11,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":12,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":13,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":14,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":15,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":16,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":17,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":18,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":19,"name":null,"tableId":null}],"tables":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listResources","summary":"List spaces at a location","description":"Lists spaces configured at a location, including their positions. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Resource"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440007","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","kind":"room","name":"Studio A","description":"Heated room with mirrors","capacity":20,"positionLayout":"list","hoursByDay":{"sat":{"start":"11:00","end":null},"sun":{"closed":true}},"seating":"door","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"imageUrl":null,"positions":[{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":0,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":1,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":2,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":3,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":4,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":5,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":6,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":7,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":8,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":9,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":10,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":11,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":12,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":13,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":14,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":15,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":16,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":17,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":18,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":19,"name":null,"tableId":null}],"tables":[]}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/resources/{id}":{"get":{"operationId":"getResource","summary":"Get a space","description":"Returns a space by ID, including its positions. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Resource"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440007","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","kind":"room","name":"Studio A","description":"Heated room with mirrors","capacity":20,"positionLayout":"list","hoursByDay":{"sat":{"start":"11:00","end":null},"sun":{"closed":true}},"seating":"door","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"imageUrl":null,"positions":[{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":0,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":1,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":2,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":3,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":4,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":5,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":6,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":7,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":8,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":9,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":10,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":11,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":12,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":13,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":14,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":15,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":16,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":17,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":18,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":19,"name":null,"tableId":null}],"tables":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateResource","summary":"Update a space","description":"Updates space metadata, capacity, or optional position names and order. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateResourceBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Resource"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440007","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","kind":"room","name":"Studio A","description":"Heated room with mirrors","capacity":20,"positionLayout":"list","hoursByDay":{"sat":{"start":"11:00","end":null},"sun":{"closed":true}},"seating":"door","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"imageUrl":null,"positions":[{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":0,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":1,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":2,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":3,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":4,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":5,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":6,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":7,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":8,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":9,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":10,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":11,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":12,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":13,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":14,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":15,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":16,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":17,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":18,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":19,"name":null,"tableId":null}],"tables":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/resources/{id}/floor":{"get":{"operationId":"getResourceFloor","summary":"Seating chart for one day","description":"Tables and the parties seated on them for one local day. The chart is one moment; parties carry their whole interval so a host move can see who else is at a table, and whether each has been checked in. Requires feature `booking.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"},{"in":"query","name":"day","schema":{"type":"string","description":"YYYY-MM-DD in the location timezone"},"required":true,"description":"YYYY-MM-DD in the location timezone"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"day":{"type":"string"},"timezone":{"type":"string"},"tables":{"type":"array","items":{"$ref":"#/components/schemas/ResourceTable"}},"parties":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"tableId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"The table it sits at; the first of them for a claim spread over several. Null when it has no seat."},"seats":{"type":"array","items":{"type":"object","properties":{"tableId":{"$ref":"#/components/schemas/Uuid"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["tableId","count"],"additionalProperties":false},"description":"Seats held per table. One entry for a booking; several for seats sold elsewhere that no single table fits."},"occurrenceId":{"type":"string"},"claim":{"type":"boolean"},"here":{"type":"boolean","description":"Checked in. Always false for seats sold elsewhere."}},"required":["id","name","partySize","startsAt","endsAt","tableId","seats","occurrenceId","claim","here"],"additionalProperties":false}}},"required":["day","timezone","tables","parties"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/resources/{id}/archive":{"post":{"operationId":"archiveResource","summary":"Archive a space","description":"Soft-archives a space. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Resource"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440007","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","kind":"room","name":"Studio A","description":"Heated room with mirrors","capacity":20,"positionLayout":"list","hoursByDay":{"sat":{"start":"11:00","end":null},"sun":{"closed":true}},"seating":"door","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"imageUrl":null,"positions":[{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":0,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":1,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":2,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":3,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":4,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":5,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":6,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":7,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":8,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":9,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":10,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":11,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":12,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":13,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":14,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":15,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":16,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":17,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":18,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":19,"name":null,"tableId":null}],"tables":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/instructor-profiles":{"post":{"operationId":"createInstructorProfile","summary":"Create an instructor profile","description":"Creates an instructor profile. Pass email (console) to find-or-create the person and grant the instructor role, or personId (API/MCP) for an existing person. Requires feature `team.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInstructorProfileBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InstructorProfile"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440008","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","bio":"RYT-200 yoga instructor","headshotUrl":"https://cdn.example.com/alex.jpg","specialties":["vinyasa","restorative"],"public":true,"instagram":"alexrivera","notifyBookings":true,"locationIds":["550e8400-e29b-41d4-a716-446655440003"],"hours":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","scheduleIds":[]}],"reservationIds":[],"person":{"id":"550e8400-e29b-41d4-a716-446655440001","email":"alex@example.com","displayName":"Alex Rivera"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listInstructorProfiles","summary":"List instructor profiles","description":"Lists instructor profiles for a business (includes person name and email). Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InstructorProfile"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440008","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","bio":"RYT-200 yoga instructor","headshotUrl":"https://cdn.example.com/alex.jpg","specialties":["vinyasa","restorative"],"public":true,"instagram":"alexrivera","notifyBookings":true,"locationIds":["550e8400-e29b-41d4-a716-446655440003"],"hours":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","scheduleIds":[]}],"reservationIds":[],"person":{"id":"550e8400-e29b-41d4-a716-446655440001","email":"alex@example.com","displayName":"Alex Rivera"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/instructor-profiles/{id}":{"get":{"operationId":"getInstructorProfile","summary":"Get an instructor profile","description":"Returns an instructor profile by ID (includes person name and email). Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InstructorProfile"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440008","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","bio":"RYT-200 yoga instructor","headshotUrl":"https://cdn.example.com/alex.jpg","specialties":["vinyasa","restorative"],"public":true,"instagram":"alexrivera","notifyBookings":true,"locationIds":["550e8400-e29b-41d4-a716-446655440003"],"hours":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","scheduleIds":[]}],"reservationIds":[],"person":{"id":"550e8400-e29b-41d4-a716-446655440001","email":"alex@example.com","displayName":"Alex Rivera"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateInstructorProfile","summary":"Update an instructor profile","description":"Updates instructor bio, headshot, or specialties. Requires feature `team.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInstructorProfileBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InstructorProfile"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440008","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","bio":"RYT-200 yoga instructor","headshotUrl":"https://cdn.example.com/alex.jpg","specialties":["vinyasa","restorative"],"public":true,"instagram":"alexrivera","notifyBookings":true,"locationIds":["550e8400-e29b-41d4-a716-446655440003"],"hours":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","scheduleIds":[]}],"reservationIds":[],"person":{"id":"550e8400-e29b-41d4-a716-446655440001","email":"alex@example.com","displayName":"Alex Rivera"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/instructor-profiles/{id}/time-off":{"get":{"operationId":"listInstructorTimeOff","summary":"List a team member's upcoming time off","description":"Time off is negative time scoped to one person — the same shape as blocked time, subtracted from every reservation they deliver and every class they teach. Rows ending in the future, soonest first (build-plan/162). Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Closure"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createInstructorTimeOff","summary":"Add time off for a team member","description":"An **all-day** entry is a `date` (optionally through `endDate`, inclusive) on the clock of `locationId` — omitted, the first site the person works at; a **timed** entry passes UTC `startsAt`/`endsAt`. Time off is business-wide: away on Tuesday is away everywhere. A window with booked dates this person is on answers `409 { code: \"stranded_dates\", dates }` and writes nothing until `strandedDates` says `keep` (a sub from the date) or `cancel` (build-plan/166). The response carries `affectedBookings`, the same count. Remove it with `DELETE /locations/closures/{closureId}`. Requires feature `team.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"endsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"strandedDates":{"$ref":"#/components/schemas/StrandedDecision"}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Closure"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/instructor-profiles/{id}/archive":{"post":{"operationId":"archiveInstructorProfile","summary":"Archive an instructor profile","description":"Soft-archives an instructor profile. Requires feature `team.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InstructorProfile"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440008","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","bio":"RYT-200 yoga instructor","headshotUrl":"https://cdn.example.com/alex.jpg","specialties":["vinyasa","restorative"],"public":true,"instagram":"alexrivera","notifyBookings":true,"locationIds":["550e8400-e29b-41d4-a716-446655440003"],"hours":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","scheduleIds":[]}],"reservationIds":[],"person":{"id":"550e8400-e29b-41d4-a716-446655440001","email":"alex@example.com","displayName":"Alex Rivera"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/offerings":{"post":{"operationId":"createOffering","summary":"Create an offering","description":"Creates a draft offering at a location. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateListingBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listOfferings","summary":"List offerings at a location","description":"Lists offerings at a location (all statuses, archived excluded). Optional `type` filter: class, session, or space; `archived=include` adds archived rows and `archived=only` returns them alone. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"},{"in":"query","name":"type","schema":{"type":"string","enum":["class","session","space"]}},{"in":"query","name":"archived","schema":{"type":"string","enum":["exclude","include","only"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Offering"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/offerings/slug-availability":{"get":{"operationId":"checkOfferingSlugAvailability","summary":"Check whether an offering slug is available at a location","description":"Live uniqueness check for the console booking-link field. When taken, includes the next free suggestion (`-2`, `-3`, …). Pass `excludeOfferingId` when editing an existing offering. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"},{"in":"query","name":"slug","schema":{"type":"string"},"required":true},{"in":"query","name":"excludeOfferingId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"available":{"type":"boolean"},"slug":{"type":"string"},"suggestion":{"type":"string"}},"required":["available","slug"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"available":true,"slug":"morning-flow"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/offerings/order":{"patch":{"operationId":"reorderOfferings","summary":"Reorder offerings of one type","description":"Sets catalog display order for offerings of one type at a location. ids must match the live set exactly (classes exclude ended). Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["class","session","space"]},"ids":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["type","ids"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Offering"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}":{"get":{"operationId":"getOffering","summary":"Get an offering","description":"Returns an offering with schedules and images. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateOffering","summary":"Update an offering","description":"A `scheduleIds` change on a class that would leave a booked date without its rule — a rule removed, or every rule replaced (a booked date belongs to its rule, so a new rule at the same time strands it) — answers `409 { code: \"stranded_dates\", dates }` and writes nothing until `strandedDates` says `keep` or `cancel`. A `capacity` below what a future date has booked answers `409 { code: \"capacity_below_booked\", dates }`: lower those dates’ seats first, or wait until they have run (build-plan/166). Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateListingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteOffering","summary":"Delete a draft","description":"Deletes a listing that is still a draft and that nobody has booked — it goes for good, photos stay in the library. A published, hidden or archived listing answers `409 { code: \"not_a_draft\" }`; a draft with a booking, a waitlist place, a series or a claim answers `409 { code: \"draft_in_use\" }` — archive those instead. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/availability-explain":{"get":{"operationId":"explainAvailability","summary":"Why these times — one day of a reservation’s or rental’s open times, explained","description":"Every start the hours allow that day, in order, each saying whether it sells (open, reduced, full, gone) and what takes it or takes seats from it, in plain words with a console link to the thing — a class date in the room and the tables it holds, another party, seats sold elsewhere, a closure, a person's time off, a class they teach, Google busy time, the listing's own times, the booking cutoff and horizon. The numbers are the grid's own. A reservation is explained one person at a time (`subjectId`). A class has dates, not a grid: 400. Requires feature `location.view`.","tags":["availability"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"},{"in":"query","name":"day","schema":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"The day, YYYY-MM-DD in the location's zone."},"required":true,"description":"The day, YYYY-MM-DD in the location's zone."},{"in":"query","name":"subjectId","schema":{"description":"Reservations: the one person of the pool to explain; the first when absent. Ignored for a rental.","$ref":"#/components/schemas/Uuid"},"description":"Reservations: the one person of the pool to explain; the first when absent. Ignored for a rental."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AvailabilityExplanation"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/overview":{"get":{"operationId":"getOfferingOverview","summary":"Get an offering’s upcoming dates","description":"The next 30 days of dates for one offering, in its location timezone — each row with its end, live capacity, instructors and space. Draft and hidden offerings included. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingOverview"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/share":{"get":{"operationId":"getOfferingShare","summary":"Get an offering as a post to share","description":"The offering’s public link, its description as plain text, its price and its link-preview photo (JPEG), for a post the merchant pastes into Facebook (build-plan/233). `blocked` says why the link would not open for a stranger — draft, hidden, archived or password. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingShare"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/slug":{"patch":{"operationId":"updateOfferingSlug","summary":"Override an offering slug (unique per location)","description":"Override an offering slug (unique per location) Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"}},"required":["slug"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/slug/revert":{"post":{"operationId":"revertOfferingSlug","summary":"Revert an offering slug to auto-generated from the current name","description":"Revert an offering slug to auto-generated from the current name Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/duplicate":{"post":{"operationId":"duplicateOffering","summary":"Copy an offering as a new draft","description":"Copies an offering — price, times, instructors, photos and rules — as a new draft. Pass `name` to name the copy; without it the copy is named “… (copy)”. Schedules are cloned, so retiming the copy leaves the original alone. The booking link regenerates from the copy’s name. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/publish":{"post":{"operationId":"publishOffering","summary":"Show an offering for booking","description":"Shows an offering for booking (draft or hidden → bookable). Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/hide":{"post":{"operationId":"hideOffering","summary":"Hide an offering from booking","description":"Hides a bookable offering — stays in Admin, not bookable. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/archive":{"post":{"operationId":"archiveOffering","summary":"Archive an offering","description":"Retires the listing; bookings stay. A class with future booked dates answers `409 { code: \"stranded_dates\", dates }` and archives nothing until the body says `strandedDates: \"keep\"` (the dates still run, flagged on the calendar) or `\"cancel\"` (build-plan/166). Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"strandedDates":{"$ref":"#/components/schemas/StrandedDecision"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Offering"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/series":{"get":{"operationId":"listLocationSeries","summary":"List series at a location","description":"Lists series at a location. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Series"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{id}/series/preview":{"get":{"operationId":"previewSeries","summary":"Preview series dates","description":"Projects the dates a class series would meet for the given start and number of dates or end date, before anything is saved. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ListingIdParam"},{"in":"query","name":"startsOn","schema":{"type":"string"},"required":true},{"in":"query","name":"sessions","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"in":"query","name":"sessionCount","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},{"in":"query","name":"endsOn","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"occurrenceId":{"type":"string"},"scheduleId":{"$ref":"#/components/schemas/Uuid"},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"localStart":{"type":"string"},"localEnd":{"type":"string"},"timezone":{"type":"string"}},"required":["occurrenceId","scheduleId","startsAt","endsAt","localStart","localEnd","timezone"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"occurrenceId":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","localStart":"2026-09-15T17:00:00.000-06:00","localEnd":"2026-09-15T19:00:00.000-06:00","timezone":"America/Denver"}],"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable (`unprocessable`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{id}/series":{"get":{"operationId":"listOfferingSeries","summary":"List series on an offering","description":"Lists series on a class offering. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Series"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createSeries","summary":"Create a series","description":"Creates a draft series on a class offering. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSeriesBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable (`unprocessable`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/series/{id}":{"get":{"operationId":"getSeries","summary":"Get a series","description":"Returns a series with its materialized dates and derived fields. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SeriesIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateSeries","summary":"Update a series","description":"Updates a series. Date changes are refused (409) once anyone has enrolled. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SeriesIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSeriesBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable (`unprocessable`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"archiveSeries","summary":"Archive a series","description":"Archives a series with zero enrollments and returns its dates to drop-in. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SeriesIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/series/{id}/publish":{"post":{"operationId":"publishSeries","summary":"Publish a series","description":"Materializes the series' dates, stamps series_id, and sets status published. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SeriesIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable (`unprocessable`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/series/{id}/hide":{"post":{"operationId":"hideSeries","summary":"Hide a series","description":"Hides a series from customers without cancelling enrollments. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SeriesIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/series/{id}/overview":{"get":{"operationId":"getSeriesOverview","summary":"Series overview — roster, dates, money collected","description":"Series overview — roster, dates, money collected Requires feature `booking.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/SeriesIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SeriesOverview"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}":{"patch":{"operationId":"updateOccurrence","summary":"Change one class date: who teaches it, which room, how many spots","description":"Change one class date: who teaches it, which room, how many spots Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOccurrenceBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Occurrence"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"removeOccurrence","summary":"Take back a class date added by mistake — a one-off nobody has booked","description":"Deletes the date’s row, unhooks its single-date rule from the class, and deletes the rule when nothing else uses it, with `occurrence.removed`. No email, no refund, nothing left on the calendar. A date with bookings, spots sold elsewhere, a waitlist, a series, or a repeating rule is 409: cancel it instead. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RemovedOccurrence"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/cancel":{"post":{"operationId":"cancelOccurrence","summary":"Cancel one class date — a series date keeps the series, a drop-in date refunds its bookings","description":"Gated on `expectedEffect` — declare it first with `POST /businesses/{businessId}/money-effects`, action `occurrence.cancel`. A drop-in date refunds every live seat in full; a series date moves nothing. Requires feature `booking.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelOccurrenceBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Occurrence"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable (`unprocessable`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/enrollments/{enrollmentId}/cancel":{"post":{"operationId":"cancelMyEnrollment","summary":"Cancel my series enrollment","description":"Cancel my series enrollment","tags":["me"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/EnrollmentIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Enrollment"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/availability":{"get":{"operationId":"getAvailability","summary":"Get projected availability slots","description":"Projects open slots for a location or offering in a date range.","tags":["availability"],"parameters":[{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"offeringId","schema":{"$ref":"#/components/schemas/Uuid"}},{"in":"query","name":"scheduleId","schema":{"$ref":"#/components/schemas/Uuid"}},{"in":"query","name":"resourceId","schema":{"$ref":"#/components/schemas/Uuid"}},{"in":"query","name":"instructorId","schema":{"description":"Reservations: read one team member's slots instead of the whole pool.","$ref":"#/components/schemas/Uuid"},"description":"Reservations: read one team member's slots instead of the whole pool."},{"in":"query","name":"from","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true},{"in":"query","name":"to","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OccurrenceSlot"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","localStart":"2026-08-01T12:00:00","localEnd":"2026-08-01T13:00:00","timezone":"America/Denver","capacityTotal":20,"capacityRemaining":5,"maxPartySize":null,"capacityByStatus":{"held":0,"confirmed":5,"completed":0,"noShow":0,"elsewhere":0},"status":"open","materialized":false,"instructorIds":[]}],"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/occurrence":{"get":{"operationId":"getOccurrence","summary":"Get a single bookable slot","description":"Returns one projected slot with capacity state.","tags":["availability"],"parameters":[{"in":"query","name":"occurrenceId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"offeringId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"from","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},{"in":"query","name":"to","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OccurrenceSlot"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","localStart":"2026-08-01T12:00:00","localEnd":"2026-08-01T13:00:00","timezone":"America/Denver","capacityTotal":20,"capacityRemaining":5,"maxPartySize":null,"capacityByStatus":{"held":0,"confirmed":5,"completed":0,"noShow":0,"elsewhere":0},"status":"open","materialized":false,"instructorIds":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/occurrences/materialize":{"post":{"operationId":"materializeOccurrence","summary":"Materialize a bookable slot into a booked time","description":"Creates the booked-time row for a slot when capacity is reserved.","tags":["availability"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterializeOccurrenceBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Occurrence"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","timezone":"America/Los_Angeles","capacityOverride":null,"resourceId":null,"seriesId":null,"instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{locationId}/is-open":{"get":{"operationId":"isLocationOpen","summary":"Check whether a location is currently open","description":"Checks whether a location is open right now per its hours schedule.","tags":["availability"],"parameters":[{"$ref":"#/components/parameters/LocationIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/IsLocationOpenResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"open":true,"reason":null},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/timeline":{"get":{"operationId":"getBookingTimeline","summary":"Get booking event timeline","description":"Returns chronological domain events and pending tasks for a booking. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimelineItem"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"kind":"event","id":"550e8400-e29b-41d4-a716-446655440020","type":"booking.created","at":"2026-07-24T12:00:00.000Z","event":{"id":"550e8400-e29b-41d4-a716-446655440020","type":"booking.created","occurredAt":"2026-07-24T12:00:00.000Z","businessId":"550e8400-e29b-41d4-a716-446655440002","subject":{"type":"booking","id":"550e8400-e29b-41d4-a716-446655440005"},"actor":{"type":"customer","id":"550e8400-e29b-41d4-a716-446655440001","name":null},"data":{"partySize":1}}}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/team":{"get":{"operationId":"listTeam","summary":"List team members","description":"Lists team members with roles and person profiles. Requires feature `team.view`.","tags":["access"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"userRole":{"id":"550e8400-e29b-41d4-a716-446655440015","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"roles":["owner"],"featureOverrides":{"grant":["booking.manage"],"revoke":[]},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"person":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"instructorProfile":null,"hasPin":false,"phone":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createTeamMember","summary":"Add a team member","description":"Add a team member Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamMemberBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TeamMember"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/team/me":{"get":{"operationId":"getMyTeamMember","summary":"The caller’s own team row","description":"An instructor’s Team door. Returns that person’s row and nothing else, so it does not require `team.view`. Requires feature `location.view`.","tags":["access"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"businessId":{"$ref":"#/components/schemas/Uuid"},"member":{"$ref":"#/components/schemas/TeamMember"}},"required":["businessId","member"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/user-roles":{"get":{"operationId":"listUserRoles","summary":"List user roles for a business","description":"Lists raw user-role grants for a business. Requires feature `team.view`.","tags":["access"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UserRole"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440015","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"roles":["owner"],"featureOverrides":{"grant":["booking.manage"],"revoke":[]},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"grantUserRole","summary":"Grant a user role","description":"Grants roles and optional feature overrides to a person already on this team; anyone new is added by email (`POST /businesses/{businessId}/team`). Session only — an API key or OAuth token never grants a role. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantUserRoleBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UserRole"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440015","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"roles":["owner"],"featureOverrides":{"grant":["booking.manage"],"revoke":[]},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/features":{"get":{"operationId":"listBusinessFeatures","summary":"List enabled business features","description":"Lists enabled features and effective access for the caller. Requires feature `business.view`.","tags":["access"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/EffectiveAccess"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"businessEnabled":["booking.view","booking.manage"],"userGranted":["booking.manage"],"effective":["booking.view","booking.manage"]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"setBusinessFeatures","summary":"Set enabled business features","description":"Replaces the enabled feature set for a business. Session only. Requires feature `business.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetBusinessFeaturesBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/EffectiveAccess"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"businessEnabled":["booking.view","booking.manage"],"userGranted":["booking.manage"],"effective":["booking.view","booking.manage"]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/user-roles/{id}":{"patch":{"operationId":"updateUserRole","summary":"Update a user role","description":"Updates roles or feature overrides on an existing grant, and this business’s contact mobile for the person (`phone`). A changed `name` is accepted only on your own row — a person’s name is theirs. Session only. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/UserRoleIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRoleBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UserRole"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440015","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"roles":["owner"],"featureOverrides":{"grant":["booking.manage"],"revoke":[]},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/user-roles/{id}/invite":{"post":{"operationId":"sendTeamInvite","summary":"Email a team member their invite again","description":"Email a team member their invite again Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/UserRoleIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TeamInviteResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/user-roles/{id}/archive":{"post":{"operationId":"archiveUserRole","summary":"Archive a user role","description":"Soft-archives a user-role grant. When it was the person’s last role here, their PIN, the PINs they issued, the terminals they paired, their teaching profile, the calendar and social connections they authorised, and their API keys and OAuth grants here go with it. Session only. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/UserRoleIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UserRole"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440015","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"roles":["owner"],"featureOverrides":{"grant":["booking.manage"],"revoke":[]},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/waitlist/join":{"post":{"operationId":"joinWaitlist","summary":"Join the waitlist for a date","description":"Adds a customer to the waitlist for a full date. Requires feature `booking.manage`.","tags":["waitlist"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinWaitlistBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WaitlistEntry"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440016","businessId":"550e8400-e29b-41d4-a716-446655440002","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","offeringId":"550e8400-e29b-41d4-a716-446655440004","customerId":"550e8400-e29b-41d4-a716-446655440006","partySize":1,"status":"waiting","offeredBookingId":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/waitlist/{entryId}":{"get":{"operationId":"getWaitlistEntry","summary":"Get a waitlist entry","description":"Returns a waitlist entry and offer status. Requires feature `booking.view`.","tags":["waitlist"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/EntryIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WaitlistEntry"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440016","businessId":"550e8400-e29b-41d4-a716-446655440002","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","offeringId":"550e8400-e29b-41d4-a716-446655440004","customerId":"550e8400-e29b-41d4-a716-446655440006","partySize":1,"status":"waiting","offeredBookingId":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/waitlist":{"get":{"operationId":"listWaitlistByOccurrence","summary":"List waitlist entries for a date","description":"Lists the waitlist for a date ordered by join time. Requires feature `booking.view`.","tags":["waitlist"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WaitlistEntry"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440016","businessId":"550e8400-e29b-41d4-a716-446655440002","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","offeringId":"550e8400-e29b-41d4-a716-446655440004","customerId":"550e8400-e29b-41d4-a716-446655440006","partySize":1,"status":"waiting","offeredBookingId":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/waitlist/process-expired":{"post":{"operationId":"processExpiredWaitlistOffers","summary":"Process expired waitlist offers","description":"Expires stale offers and promotes the next waiting party. Requires feature `booking.manage`.","tags":["waitlist"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProcessExpiredWaitlistResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"processed":2,"promoted":1},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/profile":{"get":{"operationId":"getMyProfile","summary":"Get my details","description":"Returns the signed-in person profile.","tags":["me"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateMyProfile","summary":"Update my details","description":"Updates the signed-in person profile fields.","tags":["me"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePersonBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Person"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/customers":{"get":{"operationId":"listMyCustomers","summary":"List my customer relationships","description":"Lists businesses where the signed-in person is a customer.","tags":["me"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MeCustomerRelationship"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"linkSource":"checkout","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"business":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","locale":"en-US","dateFormat":"MDY","bookingMessages":"email"},"smsConsentPhone":null}],"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/customers/{customerId}":{"patch":{"operationId":"updateMyCustomer","summary":"Update my mobile at a studio","description":"Updates the signed-in person's mobile on their customer record at one studio, and the SMS box beside it: `smsConsent: true` records texting consent for that exact number (a valid US or Canadian mobile is required), `false` withdraws it, omitted leaves it. Shown only when that studio prefers text. Clearing the number stops texts without STOP.","tags":["me"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/CustomerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMyCustomerBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MeCustomerRelationship"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/marketing-consents":{"get":{"operationId":"listMyMarketingConsents","summary":"List my marketing email preferences","description":"One row per Customer relationship. globallySuppressed is the platform-wide hard suppress (build-plan/108).","tags":["me"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"globallySuppressed":{"type":"boolean"},"consents":{"type":"array","items":{"type":"object","properties":{"businessId":{"$ref":"#/components/schemas/Uuid"},"businessName":{"type":"string"},"marketingConsent":{"type":"boolean"}},"required":["businessId","businessName","marketingConsent"],"additionalProperties":false}}},"required":["globallySuppressed","consents"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"globallySuppressed":false,"consents":[{"businessId":"550e8400-e29b-41d4-a716-446655440002","businessName":"Riverbend Pottery","marketingConsent":true}]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/marketing-consents/{businessId}":{"patch":{"operationId":"updateMyMarketingConsent","summary":"Update marketing email preference for one business","description":"Opting on clears a prior global suppress. Source: preferences (build-plan/108).","tags":["me"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"marketingConsent":{"type":"boolean"}},"required":["marketingConsent"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"businessId":{"$ref":"#/components/schemas/Uuid"},"businessName":{"type":"string"},"marketingConsent":{"type":"boolean"},"globallySuppressed":{"type":"boolean"}},"required":["businessId","businessName","marketingConsent","globallySuppressed"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"businessId":"550e8400-e29b-41d4-a716-446655440002","businessName":"Riverbend Pottery","marketingConsent":true,"globallySuppressed":false},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/bookings":{"get":{"operationId":"listMyBookings","summary":"My bookings","description":"Lists upcoming and past bookings for the signed-in person. Optional `businessId` filters to one business; `limit` caps history (default 20) while upcoming stays unbounded.","tags":["me"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"query","name":"businessId","schema":{"$ref":"#/components/schemas/Uuid"}},{"in":"query","name":"limit","schema":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MeBookingsResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"upcoming":[{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[],"businessName":"Sunrise Studio","locationName":"Downtown Studio","locationTimezone":"America/Denver","offeringName":"Morning Flow","listingSlug":"morning-flow","occurrenceStartsAt":"2026-08-01T18:00:00.000Z","occurrenceEndsAt":"2026-08-01T19:00:00.000Z"}],"past":[],"pastHasMore":false},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/memberships":{"get":{"operationId":"listMyMemberships","summary":"List my memberships","description":"Lists the passes and memberships the signed-in person holds across businesses, each with its owned card as inline SVG. Ended ones (expired, canceled) are included only as cards, the three most recent per business.","tags":["me"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MeMembershipsResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"memberships":[{"id":"550e8400-e29b-41d4-a716-446655440011","businessId":"550e8400-e29b-41d4-a716-446655440002","businessName":"Sunrise Studio","customerId":"550e8400-e29b-41d4-a716-446655440006","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","planName":"Unlimited Monthly","billingPeriod":"monthly","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","creditsRemaining":500,"benefits":[{"type":"credit","config":{"amount":10,"period":"monthly","scope":"all","rollover":false}}],"ownedCardSvg":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 428 270\" width=\"640\" height=\"404\" role=\"img\" aria-label=\"Unlimited Monthly: Jordan Lee, 5 credits left\">…</svg>","walletLinks":{"apple":null,"google":null}}]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/subscriptions":{"get":{"operationId":"listMySubscriptionsForListing","summary":"My subscriptions to a listing","description":"The signed-in person's live subscriptions to one listing sold by subscription, so its page shows Manage subscription in place of Subscribe at a weekly time they hold (build-plan/280).","tags":["me"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"query","name":"offeringId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MeListingSubscriptionsResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/bookings/{bookingId}/cancel":{"post":{"operationId":"cancelMyBooking","summary":"Cancel my booking","description":"Customer self-service cancellation within policy windows.","tags":["me"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Booking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/bookings/{bookingId}/reschedule":{"post":{"operationId":"rescheduleMyBooking","summary":"Reschedule my booking","description":"Customer self-service reschedule to another open date or time, inside the listing's cancellation cutoff.","tags":["me"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescheduleBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Booking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/slugs/{slug}":{"get":{"operationId":"resolveStorefrontSlug","summary":"Resolve a root slug to a business or location","description":"Resolve a root slug to a business or location","tags":["storefront"],"parameters":[{"in":"path","name":"slug","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"business"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"type":"null"}},"required":["type","businessId","locationId"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"location"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"}},"required":["type","businessId","locationId"],"additionalProperties":false}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/slugs/{locationSlug}/live":{"get":{"operationId":"getStorefrontLive","summary":"Get a location’s live walk-in projection","description":"The public walk-in bar’s payload (build-plan/180): whether the location is open, how full its walk-in rooms are, and where to book. 404 unless the location has walk-in capacity, has turned the public bar on, and bookings are not paused.","tags":["storefront"],"parameters":[{"in":"path","name":"locationSlug","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"open":{"type":"boolean"},"level":{"anyOf":[{"type":"string","enum":["plenty","filling_up","nearly_full","full"]},{"type":"null"}]},"label":{"type":"string"},"spotsOpen":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"nextSpotsAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"bookUrl":{"type":"string"},"asOf":{"type":"string"}},"required":["open","level","label","spotsOpen","nextSpotsAt","bookUrl","asOf"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/slugs/{locationSlug}/{listingSlug}":{"get":{"operationId":"resolveStorefrontListingSlug","summary":"Resolve a location + offering slug pair","description":"Resolve a location + offering slug pair","tags":["storefront"],"parameters":[{"in":"path","name":"locationSlug","schema":{"type":"string"},"required":true},{"in":"path","name":"listingSlug","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"}},"required":["offeringId"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/businesses/{businessId}":{"get":{"operationId":"getStorefrontBusiness","summary":"Get a business page","description":"Public business profile with location summaries for embed.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontBusinessProfile"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","locations":[{"id":"550e8400-e29b-41d4-a716-446655440003","name":"Downtown Studio","slug":"sunrise-studio","address":"123 Main St, Denver, CO","timezone":"America/Denver"}]},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/locations/{locationId}":{"get":{"operationId":"getStorefrontLocation","summary":"Get a location page","description":"Public location profile with hours for embed.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/LocationIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontLocationProfile"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"timezone":"America/Denver","hours":{"timezone":"America/Denver","schedule":{"name":"Regular hours","rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","timezone":"America/Denver"}}},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/locations/{locationId}/offerings":{"get":{"operationId":"listStorefrontListings","summary":"List published offerings at a location","description":"Cursor-paginated published offerings at a location.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/LocationIdParam"},{"in":"query","name":"cursor","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontPaginatedListings"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"items":[{"id":"550e8400-e29b-41d4-a716-446655440004","name":"Morning Flow","slug":"morning-flow","description":"All-levels vinyasa","type":"class","priceAmount":3000,"priceCurrency":"USD","image":{"url":"https://cdn.example.com/class.jpg","sortOrder":0,"altText":null}}],"nextCursor":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{id}":{"get":{"operationId":"getStorefrontListing","summary":"Get a published offering","description":"Public offering detail with schedules and team members.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontListingDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440004","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","name":"Morning Flow","slug":"morning-flow","description":"All-levels vinyasa","priceAmount":3000,"priceCurrency":"USD","depositType":"percent","depositAmount":50,"capacity":20,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"images":[{"url":"https://cdn.example.com/class.jpg","sortOrder":0,"altText":null}],"schedules":[{"id":"550e8400-e29b-41d4-a716-446655440014","name":"Weekday mornings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","durationMinutes":60}],"instructors":[{"id":"550e8400-e29b-41d4-a716-446655440008","bio":"RYT-200","headshotUrl":null,"specialties":["vinyasa"]}],"addOns":[{"productId":"550e8400-e29b-41d4-a716-446655440027","name":"Bisque piece","required":true,"maxPerSpot":null,"variants":[{"variantId":"550e8400-e29b-41d4-a716-446655440028","name":"Mug","priceAmount":1200,"available":true,"lastOne":false}]}]},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{id}/series":{"get":{"operationId":"getStorefrontListingSeries","summary":"List published series for an offering","description":"List published series for an offering","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StorefrontSeries"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{id}/availability":{"get":{"operationId":"getStorefrontListingAvailability","summary":"Get a published offering’s availability","description":"Public availability slots for an offering.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"},{"in":"query","name":"instructorId","schema":{"description":"Reservations: one team member's slots. Omit for everyone who can take it (Anyone).","$ref":"#/components/schemas/Uuid"},"description":"Reservations: one team member's slots. Omit for everyone who can take it (Anyone)."},{"in":"query","name":"from","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true},{"in":"query","name":"to","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontAvailability"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","locationId":"550e8400-e29b-41d4-a716-446655440003","slots":[{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","localStart":"2026-08-01T12:00:00","localEnd":"2026-08-01T13:00:00","timezone":"America/Denver","capacityTotal":20,"capacityRemaining":5,"maxPartySize":null,"capacityByStatus":{"held":0,"confirmed":5,"completed":0,"noShow":0,"elsewhere":0},"status":"open","materialized":false,"instructorIds":[]}]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{id}/quote":{"post":{"operationId":"quoteStorefrontListing","summary":"Quote a published offering","description":"Ephemeral price + optional availability for a published offering. `occurrenceId` is optional — omit it for a price-only preview (`availability` is null). A verified session includes `memberOffer` so the booking page can state credit cost, credits left, discount, or Included.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontQuoteBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontQuoteResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"quote":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"availability":{"available":true,"capacityRemaining":5,"status":"open"},"creditsApplied":0,"creditRedemptionAvailable":false,"appliedMembershipId":null,"accessAllowed":true,"memberOffer":null,"discount":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{id}/waitlist":{"post":{"operationId":"joinStorefrontWaitlist","summary":"Join a full date's waitlist","description":"Customer-facing waitlist join. Guest email or a signed-in session; idempotent per customer per date. Rejected when the date still has room (\"book directly\"). When a spot frees, the front of the line receives a real held booking and an emailed pay link.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontWaitlistJoinBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontWaitlistJoinResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{id}/subscription-waitlist":{"post":{"operationId":"joinStorefrontSubscriptionWaitlist","summary":"Join a full subscription's waitlist","description":"For a class sold by subscription that is full at the weekly time wanted (or every session): a place in line. Guest email or a signed-in session; idempotent per customer and time. Refused with 409 `not_full` while Subscribe would sell, and `already_a_member` for a time already subscribed to. When a spot opens, the first in line is emailed a cart holding the subscription's sessions for two hours.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontSubscriptionWaitlistJoinBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontSubscriptionWaitlistJoinResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/waitlist/leave":{"post":{"operationId":"leaveStorefrontWaitlist","summary":"Leave a waitlist","description":"Takes a place off a date's or a subscription's waitlist with the `leaveToken` its join answered — no session needed. A place that was offered gives its spot back and the next in line is offered it. Idempotent: a place no longer in line answers `left: false`.","tags":["storefront"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontWaitlistLeaveBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontWaitlistLeaveResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts":{"post":{"operationId":"createCart","summary":"Create a cart","description":"Opens a cart and returns its token. Pass an `item` to add the first booking in the same call — \"book now\" is a one-item cart.","tags":["storefront"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCartBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}":{"get":{"operationId":"getCart","summary":"Get a cart by token","description":"Items with live per-item state (`held` / `available` / `unavailable` / `confirmed`) and derived totals. A checked-out cart renders as a receipt. An optional verified session overlays a downward member re-quote on the caller's own items so credits show before Pay; the stored snapshot is unchanged until checkout. A one-time pass line in the cart prices the lines it covers (scope, `credit_cost` × spots, or free) for anyone — it is being bought now, not stored (MDH-113); membership lines carry `passCover`. Once a payment is in flight the stored snapshots are returned as they are.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"},{"in":"query","name":"others","schema":{"description":"Comma-separated booking ids the shopper marked \"Book for someone else\". Neither a pass in the cart nor the member's credits cover those lines, so the preview does not either.","type":"string"},"description":"Comma-separated booking ids the shopper marked \"Book for someone else\". Neither a pass in the cart nor the member's credits cover those lines, so the preview does not either."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/answer-suggestions":{"get":{"operationId":"getCartAnswerSuggestions","summary":"Remembered answers for this cart","description":"What the signed-in customer answered these same questions before, offered back so a returning customer taps instead of retypes. Scoped to the caller's own history with this business — the cart token alone does not read it, so an operator pay-link opened by someone else returns nothing. Values a question no longer accepts (a since-removed option) are filtered out; empty for guests, receipts, and carts with no questions.","tags":["storefront"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AnswerSuggestions"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/offerings/{offeringId}/answer-suggestions":{"get":{"operationId":"getListingAnswerSuggestions","summary":"Last time, for the Book sheet","description":"What the signed-in customer answered a published listing's questions before (build-plan/239) — Last time on the listing page's Book sheet, offered beside each field, never filled. The caller's own history with this business; values a question no longer accepts are filtered out; never a Checkbox's tick. Empty when the listing asks nothing.","tags":["storefront"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"offeringId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AnswerSuggestions"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/items":{"post":{"operationId":"addCartItem","summary":"Add an item to a cart","description":"Creates a held booking on a 10-minute TTL and attaches it to the cart. With `variantId` and `quantity` it holds a product line instead (architecture/26): the units come off what can be sold under the option's lock, and `409 out_of_stock` carries `available` when there are too few.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CartItemBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"clearCartItems","summary":"Empty a cart","description":"Removes every item from an open cart — the same as deleting each one. Held bookings and enrollments are canceled. The cart stays open. 409 while a payment for the cart is in flight.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/items/{itemId}":{"delete":{"operationId":"removeCartItem","summary":"Remove an item from a cart","description":"Cancels the held booking, releasing its capacity. Removing a pass line re-prices every class it covered back to its cash quote (MDH-113). 409 while a payment for the cart is in flight — that charge was fixed for these items.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"},{"$ref":"#/components/parameters/CartItemIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/items/{itemId}/answers":{"put":{"operationId":"setCartItemAnswers","summary":"Set a cart line's answers","description":"A booking or series line's answers, replaced whole (build-plan/239) — checkout's Edit, and the questions it asks in place on a line nobody answered (a pay link, a plain embed). Each answer is checked as at checkout but never for Required; checkout asks what the line still owes (`answersMissing`). An answer to a question the line does not ask is dropped; a value that is not an answer is a 400 naming the question. 409 while a payment for the cart is in flight. Possession of the token is authorization.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"},{"$ref":"#/components/parameters/CartItemIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CartItemAnswersBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/cancel":{"post":{"operationId":"cancelStorefrontCart","summary":"Cancel a cart","description":"Revokes the cart by token: remaining held bookings are canceled and the cart becomes `canceled`. Possession of the token is authorization.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/holds":{"post":{"operationId":"refreshCartHolds","summary":"Extend or re-acquire cart holds","description":"Refreshes every held booking in an open cart under the standard capacity guard — the same re-acquire checkout uses. Sold-out items are skipped; the response carries live per-item state, priced as `GET /storefront/carts/{token}` prices it.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"},{"in":"query","name":"others","schema":{"description":"Booking ids marked \"Book for someone else\" — as on `GET /storefront/carts/{token}`.","type":"string"},"description":"Booking ids marked \"Book for someone else\" — as on `GET /storefront/carts/{token}`."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/settle":{"post":{"operationId":"settleCart","summary":"Settle a cart from its provider’s record","description":"The page's ask while it waits on a payment: read the cart's live attempt back from its provider and settle it when the provider says the money moved — Stripe's intent when its webhook is late or lost; on TRX, a sale whose answer never arrived (the checkout answered 409 `payment_unconfirmed`), looked for in TRX's own record (architecture/05 § Settling from the provider's record). The cart as it then stands, with `payment`: `requires_action` while a TRX sale is still being confirmed, `captured` (and the cart `checked_out`) once it is found, `failed` with `decline.code` `not_charged` when TRX turns out to hold none, or `card_declined` with the one sentence every refused card gets when TRX's record says the card was refused (its code and words stay on the cart's `checkout_attempt` row, build-plan/279) — the cart is then free for another Book. Idempotent: a settled cart reads back as it is and nothing is sold twice.","tags":["storefront"],"security":[{},{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CartSettleResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/card-session":{"post":{"operationId":"openCardSession","summary":"Open the cart’s card fields (TRX)","description":"For a business on `trx` (`business.paymentsProvider`): what the checkout page needs to render TRX's card fields in its own form — the script to load (`scriptUrl`, `window.PayPageJS`) and the `sessionData` for `PayPageJS.initialize` (`clientId`, `sessionId`, `payPageId`) — for the amount the cart owes now. Stateless: every call opens a new session at TRX and nothing is stored, so there is nothing to read back. Nothing here moves money: the page's Book calls `getEncryptedCardData()` and sends the result as `card` on `POST …/checkout`. With `{ wallets: true }`, where Apple Pay and Google Pay are offered (`TRX_WALLETS_ENABLED`, the platform's own host — never a studio's custom domain; build-plan/213 ticket 1.4), the session also allows TRX's wallet buttons and the answer carries `wallets` with the amount it was opened for; elsewhere the answer is a plain card session. 409 `not_available_on_provider` for a Stripe business; 400 when nothing is due or the cart is closed; 403 until the merchant login is verified.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardSessionBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CardSession"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/checkout":{"post":{"operationId":"checkoutCart","summary":"Check out a cart","description":"One charge for the sum of what is due now, on the business's card provider (`business.paymentsProvider`: `stripe` on its connected account, `trx` on its own merchant account). A body `provider` naming the other card provider is a 400 naming the business's; `manual` is the desk's cash. Every hold is re-acquired first; if any item has sold out the call fails with `item_unavailable` and nothing is charged. Guests check out with a bare `email` in the body — no verification; a signed-in member sends a session bearer instead and their items re-quote at member pricing, downward only. An unverified email never unlocks member pricing, credits, or account data. **Stripe** answers `payment.clientSecret` for the browser to confirm, and the cart settles afterwards. **TRX is charged inside this request**, on the encrypted `card` the page's card fields produced: the answer is the cart already `checked_out` with every booking confirmed and `payment.status` `captured`. Without `card` a TRX checkout is 409 (`details.status: card_required`). Where Apple Pay and Google Pay are offered (build-plan/213 ticket 1.4) the `card` may be a wallet's — `card.wallet` with its `cardSecurity` cryptogram — charged the same way and never saved, so a deposit paid by wallet leaves no card on file; `card.wallet` anywhere wallets are not offered is a 400. A card TRX refuses is **402 `card_declined`** with the one sentence every refused card gets — *That card was declined. Try another card.* — and no `details`: TRX's response code and words are written to the cart's `checkout_attempt` row and the `[pay]` log, never to the page, because a decline's reason is an authorization oracle for card testing (build-plan/279). A partial approval is voided and answers the same. The cart stays open with its holds and the next checkout is a new attempt. When TRX's answer never arrives the call is **409 with `details.status: payment_unconfirmed`** (*We are confirming your payment. Do not pay again.*): the card may have been charged, a repeated checkout answers the same 409 and charges nothing, and `POST …/settle` says what became of it. **The server never charges more than the page showed**: a checkout that sends `expectedAmount` (required with `card`) is held to it, and when the amount due now — computed under the cart's lock — is not that amount, higher or lower, the call is **409 with `details.status: amount_changed`**, `details.amountDueNow`, `details.currency` and `details.cart` (the cart as it prices now): nothing was charged and no payment was made, the cart is still open, and the page shows the new total and asks again.","tags":["storefront"],"security":[{},{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutCartBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CheckoutResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/bookings/{bookingId}":{"get":{"operationId":"getStorefrontBooking","summary":"Get a booking by manage-link id","description":"Possession of the booking uuid authorizes this read. Returns the customer-facing view (masked email, money, policy). Unknown and malformed ids both 404 identically.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ManageBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","reference":"BK-550E8400","status":"confirmed","listing":{"id":"550e8400-e29b-41d4-a716-446655440004","name":"Vinyasa Flow","slug":"vinyasa-flow","type":"class","capacity":12,"bookingHorizonDays":28,"spotsLeft":"few","confirmationMessage":"Bring a mat.","meetingUrl":null,"meetingInstructions":null},"when":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","timezone":"America/Denver","dayLabel":"Sat, Aug 1, 2026","timeRangeLabel":"12:00 PM – 1:00 PM","timezoneLabel":"America/Denver"},"location":{"name":"Main Hall","slug":"main-hall","address":"9 Link St","lat":null,"lng":null,"timezone":"America/Denver","contactEmail":"hello@example.com","contactPhone":null},"business":{"name":"Sunrise Studio","slug":"sunrise-studio","contactEmail":"hello@example.com"},"party":{"size":1,"customerName":"Alex Rivera","customerEmailMasked":"a•••@example.com"},"money":{"currency":"USD","amountTotal":4500,"amountPaid":4500,"amountDue":0,"amountTotalLabel":"$45.00","amountPaidLabel":"$45.00","amountDueLabel":"$0.00","refundExpected":true,"refundLabel":"$45.00","balanceCollectAtLabel":null},"policy":{"canCancelOnline":true,"canRescheduleOnline":true,"inCancelWindow":true,"refundExpected":true,"changesCloseAt":"2026-07-31T18:00:00.000Z","changesCloseAtLabel":"Fri, Jul 31, 2026, 12:00 PM","closedReason":null},"answers":[],"cartHref":null,"locale":"en-US","dateFormat":"MDY"},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/bookings/{bookingId}/availability":{"get":{"operationId":"getStorefrontBookingAvailability","summary":"Availability for rescheduling a booking","description":"Open slots for the same offering that can hold the booking's spots. The current date is omitted. Closed by policy → `reschedule_closed`.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"},{"in":"query","name":"instructorId","schema":{"description":"Reservations: one team member's slots. Omit for everyone who can take it (Anyone).","$ref":"#/components/schemas/Uuid"},"description":"Reservations: one team member's slots. Omit for everyone who can take it (Anyone)."},{"in":"query","name":"from","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true},{"in":"query","name":"to","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StorefrontAvailability"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","locationId":"550e8400-e29b-41d4-a716-446655440003","slots":[{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","localStart":"2026-08-01T12:00:00","localEnd":"2026-08-01T13:00:00","timezone":"America/Denver","capacityTotal":20,"capacityRemaining":5,"maxPartySize":null,"capacityByStatus":{"held":0,"confirmed":5,"completed":0,"noShow":0,"elsewhere":0},"status":"open","materialized":false,"instructorIds":[]}]},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/bookings/{bookingId}/cancel":{"post":{"operationId":"cancelStorefrontBooking","summary":"Cancel a booking via manage link","description":"Cancels when policy allows. Reason is `customer_cancel` in-window or `customer_late_cancel` after the cutoff. Refunds follow the offering’s cutoff (late cancels do not auto-refund). Actor on the event is `customer`.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ManageBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","reference":"BK-550E8400","status":"confirmed","listing":{"id":"550e8400-e29b-41d4-a716-446655440004","name":"Vinyasa Flow","slug":"vinyasa-flow","type":"class","capacity":12,"bookingHorizonDays":28,"spotsLeft":"few","confirmationMessage":"Bring a mat.","meetingUrl":null,"meetingInstructions":null},"when":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","timezone":"America/Denver","dayLabel":"Sat, Aug 1, 2026","timeRangeLabel":"12:00 PM – 1:00 PM","timezoneLabel":"America/Denver"},"location":{"name":"Main Hall","slug":"main-hall","address":"9 Link St","lat":null,"lng":null,"timezone":"America/Denver","contactEmail":"hello@example.com","contactPhone":null},"business":{"name":"Sunrise Studio","slug":"sunrise-studio","contactEmail":"hello@example.com"},"party":{"size":1,"customerName":"Alex Rivera","customerEmailMasked":"a•••@example.com"},"money":{"currency":"USD","amountTotal":4500,"amountPaid":4500,"amountDue":0,"amountTotalLabel":"$45.00","amountPaidLabel":"$45.00","amountDueLabel":"$0.00","refundExpected":true,"refundLabel":"$45.00","balanceCollectAtLabel":null},"policy":{"canCancelOnline":true,"canRescheduleOnline":true,"inCancelWindow":true,"refundExpected":true,"changesCloseAt":"2026-07-31T18:00:00.000Z","changesCloseAtLabel":"Fri, Jul 31, 2026, 12:00 PM","closedReason":null},"answers":[],"cartHref":null,"locale":"en-US","dateFormat":"MDY"},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/bookings/{bookingId}/reschedule":{"post":{"operationId":"rescheduleStorefrontBooking","summary":"Reschedule a booking via manage link","description":"Moves the booking to another open date or time of the same offering, same number of spots. Past cutoff → `reschedule_closed`; lost the capacity race → `slot_unavailable`.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontRescheduleBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ManageBooking"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440005","reference":"BK-550E8400","status":"confirmed","listing":{"id":"550e8400-e29b-41d4-a716-446655440004","name":"Vinyasa Flow","slug":"vinyasa-flow","type":"class","capacity":12,"bookingHorizonDays":28,"spotsLeft":"few","confirmationMessage":"Bring a mat.","meetingUrl":null,"meetingInstructions":null},"when":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","timezone":"America/Denver","dayLabel":"Sat, Aug 1, 2026","timeRangeLabel":"12:00 PM – 1:00 PM","timezoneLabel":"America/Denver"},"location":{"name":"Main Hall","slug":"main-hall","address":"9 Link St","lat":null,"lng":null,"timezone":"America/Denver","contactEmail":"hello@example.com","contactPhone":null},"business":{"name":"Sunrise Studio","slug":"sunrise-studio","contactEmail":"hello@example.com"},"party":{"size":1,"customerName":"Alex Rivera","customerEmailMasked":"a•••@example.com"},"money":{"currency":"USD","amountTotal":4500,"amountPaid":4500,"amountDue":0,"amountTotalLabel":"$45.00","amountPaidLabel":"$45.00","amountDueLabel":"$0.00","refundExpected":true,"refundLabel":"$45.00","balanceCollectAtLabel":null},"policy":{"canCancelOnline":true,"canRescheduleOnline":true,"inCancelWindow":true,"refundExpected":true,"changesCloseAt":"2026-07-31T18:00:00.000Z","changesCloseAtLabel":"Fri, Jul 31, 2026, 12:00 PM","closedReason":null},"answers":[],"cartHref":null,"locale":"en-US","dateFormat":"MDY"},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/bookings/{bookingId}/feedback":{"post":{"operationId":"rateStorefrontBooking","summary":"Rate booking online, from a one-item receipt","description":"The thumb under *Booked* on `/booking/{id}?booked=1`: `up` or `down`, with one optional line on a thumbs down. One vote per checkout — keyed by the cart the booking came through, else the booking — and the last tap wins; a new vote replaces the last comment. Possession of the booking id is the capability, as for the manage link. A hold or a canceled booking is 409.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontFeedbackBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingFeedback"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/feedback":{"post":{"operationId":"rateStorefrontCart","summary":"Rate booking online, from a receipt of several","description":"The same thumb on `/cart/{token}` once the cart has checked out and booked something; the token is the capability. One vote for the whole receipt, recorded on each booking it covered. An open cart, or one that booked nothing, is 409.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontFeedbackBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingFeedback"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/membership-plans/{planId}/checkout":{"post":{"operationId":"checkoutStorefrontMembershipPlan","summary":"Buy a membership plan","description":"Buy a published plan. A guest supplies a bare `email`; a signed-in member sends a session bearer instead. Free plans create the membership immediately and return its `manageUrl`. Every paid plan — a pass, or a recurring membership whose first charge saves the card it renews on (build-plan/265 D1) — adds to a cart and returns `cartUrl` (`HOST/cart/{token}`).","tags":["storefront"],"security":[{},{"sessionBearer":[]}],"parameters":[{"in":"path","name":"planId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"cartUrl":{"type":"string","format":"uri"},"manageUrl":{"type":"string","format":"uri"},"membershipId":{"$ref":"#/components/schemas/Uuid"}},"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/memberships/{membershipId}/cancel":{"post":{"operationId":"cancelStorefrontMembership","summary":"Cancel a membership at the period end","description":"The holder cancels their recurring membership from its page (build-plan/265 D7): it stays active until the paid period ends, nothing more is charged, and the holder is told. Possession of the membership uuid is authorization; unknown and malformed ids both 404 identically. Answers the page view, with its Payment block.","tags":["storefront"],"parameters":[{"in":"path","name":"membershipId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"membershipId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string"},"statusLabel":{"type":"string"},"recordWord":{"type":"string","enum":["subscription","membership"],"description":"The customer’s word for the record (build-plan/280 D11)"},"subscription":{"anyOf":[{"type":"object","properties":{"listingName":{"type":"string"},"spotsLabel":{"type":"string","description":"\"2 spots\""},"whenLabel":{"type":"string","description":"\"Wednesdays 3:30 pm\", or \"every session\""},"sessions":{"type":"array","items":{"type":"object","properties":{"bookingId":{"$ref":"#/components/schemas/Uuid"},"label":{"type":"string","description":"\"Mon Oct 19 · 3:30 pm\""}},"required":["bookingId","label"],"additionalProperties":false}},"everyLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"\"…and every Monday and Wednesday after.\" while it renews"},"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scheduledSpots":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"A removal waiting for the term's end (build-plan/280 § Changing spots)"},"scheduledLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"\"2 spots from Nov 13\" while a removal waits"},"canChangeSpots":{"type":"boolean","description":"The sheet is offered: active, renewing on a card, not ending"},"minSpots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxSpots":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["listingName","spotsLabel","whenLabel","sessions","everyLine","spots","scheduledSpots","scheduledLine","canChangeSpots","minSpots","maxSpots"],"additionalProperties":false},{"type":"null"}],"description":"A subscription (build-plan/280): the listing it is of, its spots and its next sessions; null for a pass or a membership"},"payment":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["active","past_due","canceling","canceled","ended","paused"]},"billingMode":{"type":"string","enum":["card","manual"]},"cardLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceLabel":{"type":"string","description":"The period’s price; a subscription’s term: price per spot × spots, less its kept discount"},"periodWord":{"type":"string","enum":["week","month","year"]},"nextChargeLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"endsLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"pastDueLine":{"anyOf":[{"type":"string"},{"type":"null"}]},"endedLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A subscription ended after its last decline: what was tried"},"updateCardUrl":{"type":"string"},"passesUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"listingUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A subscription’s listing page while it sells, else its location’s — Subscribe again"},"canCancel":{"type":"boolean"},"canKeep":{"type":"boolean"},"canUpdateCard":{"type":"boolean"}},"required":["state","billingMode","cardLabel","priceLabel","periodWord","nextChargeLabel","endsLabel","pastDueLine","endedLine","updateCardUrl","passesUrl","listingUrl","canCancel","canKeep","canUpdateCard"],"additionalProperties":false},{"type":"null"}]}},"required":["membershipId","status","statusLabel","recordWord","subscription","payment"],"additionalProperties":{}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"keepStorefrontMembership","summary":"Keep a membership — take back a cancel at the period end","description":"Clears the cancel at period end while the membership has not ended (build-plan/265 D7); 409 once it has.","tags":["storefront"],"parameters":[{"in":"path","name":"membershipId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"membershipId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string"},"statusLabel":{"type":"string"},"recordWord":{"type":"string","enum":["subscription","membership"],"description":"The customer’s word for the record (build-plan/280 D11)"},"subscription":{"anyOf":[{"type":"object","properties":{"listingName":{"type":"string"},"spotsLabel":{"type":"string","description":"\"2 spots\""},"whenLabel":{"type":"string","description":"\"Wednesdays 3:30 pm\", or \"every session\""},"sessions":{"type":"array","items":{"type":"object","properties":{"bookingId":{"$ref":"#/components/schemas/Uuid"},"label":{"type":"string","description":"\"Mon Oct 19 · 3:30 pm\""}},"required":["bookingId","label"],"additionalProperties":false}},"everyLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"\"…and every Monday and Wednesday after.\" while it renews"},"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scheduledSpots":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"A removal waiting for the term's end (build-plan/280 § Changing spots)"},"scheduledLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"\"2 spots from Nov 13\" while a removal waits"},"canChangeSpots":{"type":"boolean","description":"The sheet is offered: active, renewing on a card, not ending"},"minSpots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxSpots":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["listingName","spotsLabel","whenLabel","sessions","everyLine","spots","scheduledSpots","scheduledLine","canChangeSpots","minSpots","maxSpots"],"additionalProperties":false},{"type":"null"}],"description":"A subscription (build-plan/280): the listing it is of, its spots and its next sessions; null for a pass or a membership"},"payment":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["active","past_due","canceling","canceled","ended","paused"]},"billingMode":{"type":"string","enum":["card","manual"]},"cardLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceLabel":{"type":"string","description":"The period’s price; a subscription’s term: price per spot × spots, less its kept discount"},"periodWord":{"type":"string","enum":["week","month","year"]},"nextChargeLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"endsLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"pastDueLine":{"anyOf":[{"type":"string"},{"type":"null"}]},"endedLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A subscription ended after its last decline: what was tried"},"updateCardUrl":{"type":"string"},"passesUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"listingUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A subscription’s listing page while it sells, else its location’s — Subscribe again"},"canCancel":{"type":"boolean"},"canKeep":{"type":"boolean"},"canUpdateCard":{"type":"boolean"}},"required":["state","billingMode","cardLabel","priceLabel","periodWord","nextChargeLabel","endsLabel","pastDueLine","endedLine","updateCardUrl","passesUrl","listingUrl","canCancel","canKeep","canUpdateCard"],"additionalProperties":false},{"type":"null"}]}},"required":["membershipId","status","statusLabel","recordWord","subscription","payment"],"additionalProperties":{}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/memberships/{membershipId}/spots/quote":{"post":{"operationId":"quoteStorefrontSubscriptionSpots","summary":"Quote a change to my subscription's spots","description":"The subscriber's sheet (build-plan/280 § Changing spots): what changing to `spots` would do — an add now, charged for the sessions left in the term; a removal at the term's end, no refund; the new figure at the new count with today's discount rules; a full session named in `blocked`. Possession of the subscription uuid is authorization. Nothing is written.","tags":["storefront"],"parameters":[{"in":"path","name":"membershipId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["spots"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SpotsChangeQuote"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/memberships/{membershipId}/spots":{"post":{"operationId":"changeStorefrontSubscriptionSpots","summary":"Change my subscription's spots","description":"Makes the change the sheet showed (build-plan/280 § Changing spots). `expectedAmount` is the figure on the button (the charge now, with tax): a different figure answers 409 `amount_changed` with the quote as it stands, and nothing moves. A declined card is 402 `card_declined` with one sentence, and the spots are put back. Answers the result and the page view.","tags":["storefront"],"parameters":[{"in":"path","name":"membershipId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expectedAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["spots"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"result":{"$ref":"#/components/schemas/SpotsChangeResult"},"membership":{"type":"object","properties":{"membershipId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string"},"statusLabel":{"type":"string"},"recordWord":{"type":"string","enum":["subscription","membership"],"description":"The customer’s word for the record (build-plan/280 D11)"},"subscription":{"anyOf":[{"type":"object","properties":{"listingName":{"type":"string"},"spotsLabel":{"type":"string","description":"\"2 spots\""},"whenLabel":{"type":"string","description":"\"Wednesdays 3:30 pm\", or \"every session\""},"sessions":{"type":"array","items":{"type":"object","properties":{"bookingId":{"$ref":"#/components/schemas/Uuid"},"label":{"type":"string","description":"\"Mon Oct 19 · 3:30 pm\""}},"required":["bookingId","label"],"additionalProperties":false}},"everyLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"\"…and every Monday and Wednesday after.\" while it renews"},"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"scheduledSpots":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"A removal waiting for the term's end (build-plan/280 § Changing spots)"},"scheduledLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"\"2 spots from Nov 13\" while a removal waits"},"canChangeSpots":{"type":"boolean","description":"The sheet is offered: active, renewing on a card, not ending"},"minSpots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxSpots":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["listingName","spotsLabel","whenLabel","sessions","everyLine","spots","scheduledSpots","scheduledLine","canChangeSpots","minSpots","maxSpots"],"additionalProperties":false},{"type":"null"}],"description":"A subscription (build-plan/280): the listing it is of, its spots and its next sessions; null for a pass or a membership"},"payment":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["active","past_due","canceling","canceled","ended","paused"]},"billingMode":{"type":"string","enum":["card","manual"]},"cardLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceLabel":{"type":"string","description":"The period’s price; a subscription’s term: price per spot × spots, less its kept discount"},"periodWord":{"type":"string","enum":["week","month","year"]},"nextChargeLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"endsLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"pastDueLine":{"anyOf":[{"type":"string"},{"type":"null"}]},"endedLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A subscription ended after its last decline: what was tried"},"updateCardUrl":{"type":"string"},"passesUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"listingUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A subscription’s listing page while it sells, else its location’s — Subscribe again"},"canCancel":{"type":"boolean"},"canKeep":{"type":"boolean"},"canUpdateCard":{"type":"boolean"}},"required":["state","billingMode","cardLabel","priceLabel","periodWord","nextChargeLabel","endsLabel","pastDueLine","endedLine","updateCardUrl","passesUrl","listingUrl","canCancel","canKeep","canUpdateCard"],"additionalProperties":false},{"type":"null"}]}},"required":["membershipId","status","statusLabel","recordWord","subscription","payment"],"additionalProperties":{}}},"required":["result","membership"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/memberships/{membershipId}/card-session":{"post":{"operationId":"openStorefrontMembershipCardSession","summary":"Open the update-card page’s card session","description":"What the update-card page mounts (build-plan/265 D8): on Stripe, a SetupIntent on the studio's connected account for the holder's Customer there (its client secret, the publishable key and the account for Stripe.js); on TRX, a card session for the card fields. Nothing is kept. 400 on a membership that is not charged to a card or has ended.","tags":["storefront"],"parameters":[{"in":"path","name":"membershipId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"type":"object","properties":{"provider":{"type":"string","const":"stripe"},"publishableKey":{"type":"string"},"connectedAccountId":{"type":"string"},"clientSecret":{"type":"string"},"setupIntentId":{"type":"string"},"businessName":{"type":"string"}},"required":["provider","publishableKey","connectedAccountId","clientSecret","setupIntentId","businessName"],"additionalProperties":false},{"type":"object","properties":{"provider":{"type":"string","const":"trx"},"scriptUrl":{"type":"string","format":"uri"},"clientId":{"type":"string"},"sessionId":{"type":"string"},"payPageId":{"type":"string"},"expiresAt":{"type":"string"}},"required":["provider","scriptUrl","clientId","sessionId","payPageId","expiresAt"],"additionalProperties":false}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/memberships/{membershipId}/card":{"post":{"operationId":"saveStorefrontMembershipCard","summary":"Save a new card on a membership","description":"Stripe: `setupIntentId`, the SetupIntent the page confirmed — read back from Stripe, never trusted from the page. TRX: `card`, the encrypted card the fields produced, verified by a $0.00 Auth that vaults it. Either writes a new card on file, repoints the membership and keeps the old row with `replaced_at`; on a past-due membership the renewal is tried at once and `renewal` says what it did. 402 `card_declined` when the processor says no.","tags":["storefront"],"parameters":[{"in":"path","name":"membershipId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"setupIntentId":{"type":"string"},"card":{"type":"object","properties":{"data":{"type":"string"},"keyId":{"type":"string"},"postal":{"type":"string"}},"required":["data","keyId"]}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"card":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"label":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","label"],"additionalProperties":false},"renewal":{"anyOf":[{"type":"object","properties":{"outcome":{"type":"string"},"line":{"type":"string"}},"required":["outcome","line"],"additionalProperties":false},{"type":"null"}]},"membership":{"type":"object","properties":{"status":{"type":"string"},"nextChargeLabel":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["status","nextChargeLabel"],"additionalProperties":false}},"required":["card","renewal","membership"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/questions":{"get":{"operationId":"listQuestions","summary":"List the checkout-question catalog","description":"Active (non-archived) questions for the business. Assignment to offerings happens via `questionIds` on offering create/update; customers answer once per cart at checkout.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Question"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createQuestion","summary":"Create a checkout question","description":"Adds to the business catalog. Choice types need unique options (radio/select ≥ 2, checkboxes ≥ 1); text questions take none. No branching or conditional logic — a question that must behave differently is a second question.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateQuestionBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Question"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/questions/{questionId}":{"patch":{"operationId":"updateQuestion","summary":"Update a checkout question","description":"Prompt, help text, options, and required are editable; the type is immutable (make a new question instead). Existing booking answers keep their snapshotted prompt — edits never rewrite what a customer was asked.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"path","name":"questionId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateQuestionBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Question"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/questions/{questionId}/archive":{"post":{"operationId":"archiveQuestion","summary":"Archive a checkout question","description":"Soft-archive: the question stops being asked everywhere it is assigned; answers already given stand.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"path","name":"questionId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Question"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/carts/{token}/code":{"put":{"operationId":"setCartCode","summary":"Add or remove a cart's code","description":"The one code a cart carries. A code is stored only when it applies to the cart as priced now: an unknown, paused, expired or used-up code answers 400 `code` \"That code isn't valid\"; one that wins no line \"That code doesn't apply to anything in this cart\". `null` removes it. The cart comes back priced as `GET /storefront/carts/{token}` prices it, the discount on its line. 409 while a payment for the cart is in flight.","tags":["storefront"],"security":[{},{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/CartTokenParam"},{"in":"query","name":"others","schema":{"description":"Booking ids marked \"Book for someone else\" — as on `GET /storefront/carts/{token}`.","type":"string"},"description":"Booking ids marked \"Book for someone else\" — as on `GET /storefront/carts/{token}`."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["code"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Cart"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/images":{"post":{"operationId":"uploadOfferingImage","summary":"Upload an offering photo","description":"Uploads an offering photo; re-encodes to WebP variants and returns URLs. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listOfferingImages","summary":"List offering photos","description":"Lists images for an offering in sort order. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/resources/{id}/images":{"post":{"operationId":"uploadResourceImage","summary":"Upload a space photo","description":"Uploads a space photo; re-encodes to WebP variants and returns URLs. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listResourceImages","summary":"List space photos","description":"Lists images for a space in sort order. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/instructor-profiles/{id}/images":{"post":{"operationId":"uploadInstructorImage","summary":"Upload an instructor headshot","description":"Uploads an instructor headshot (one per profile) and mirrors the md URL onto headshot_url. Requires feature `team.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listInstructorImages","summary":"List instructor headshots","description":"Lists the instructor headshot (at most one). Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/InstructorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/membership-plans/{id}/images":{"post":{"operationId":"uploadMembershipPlanImage","summary":"Upload a membership plan photo","description":"Uploads a membership plan cover photo (one per plan). Requires feature `catalog.manage`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/MembershipPlanIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listMembershipPlanImages","summary":"List membership plan photos","description":"Lists the membership plan cover photo (at most one). Requires feature `business.view`.","tags":["membership"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/MembershipPlanIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/images":{"post":{"operationId":"uploadLocationImage","summary":"Upload a location photo","description":"Uploads a location photo to its gallery. The hero is the header image, not these. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listLocationImages","summary":"List location photos","description":"Lists photos for a location in sort order. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/images/order":{"patch":{"operationId":"reorderLocationImages","summary":"Reorder location photos","description":"Sets the display order of location photos to the given id list. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderImagesBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/resources/{id}/images/order":{"patch":{"operationId":"reorderResourceImages","summary":"Reorder space photos","description":"Sets the display order of space images to the given id list. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderImagesBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/offerings/{id}/images/order":{"patch":{"operationId":"reorderOfferingImages","summary":"Reorder offering photos","description":"Sets the display order of offering images to the given id list. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ListingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderImagesBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/images/{id}":{"get":{"operationId":"getImage","summary":"Get a photo placement","description":"Get a photo placement Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ImageIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateImage","summary":"Frame a photo placement","description":"How this placement frames its photo for each shape it shows in: `wide` and `square`, each a fit (`fill` crops at x/y and zoom; `whole` shows the entire photo on a `blur` or `color` background). `null` draws it cover, centred. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ImageIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateImageBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteImage","summary":"Delete a photo","description":"Detaches a photo from its owner. The photo stays in Photos, bytes and all. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ImageIdParam"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/logo":{"post":{"operationId":"uploadLocationLogo","summary":"Upload a location logo","description":"Uploads or replaces the location logo used on its page and in emails. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadLocationLogoBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listLocationLogo","summary":"List a location's logo placement","description":"List a location's logo placement Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteLocationLogo","summary":"Remove a location logo","description":"Removes the location logo. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/locations/{id}/header":{"post":{"operationId":"uploadLocationHeader","summary":"Upload a location header image","description":"Uploads or replaces the location header image — one per location, the hero of its page. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listLocationHeader","summary":"List the location header image","description":"Lists the location header image (at most one). Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteLocationHeader","summary":"Remove a location header image","description":"Removes the location header image. The photo stays in Photos. Requires feature `location.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/LocationOwnerIdParam"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/journey":{"get":{"operationId":"listStudioJourney","summary":"List the studio journey","description":"The studio's steps in order, each with its server-built sentence. Confirmation, Check in and Collect balance are always present. Requires feature `business.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/JourneyStep"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/journey/steps":{"post":{"operationId":"createStudioJourneyStep","summary":"Add a studio journey step","description":"A new message or milestone on every booking. Added at the end of the studio list. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJourneyStepBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/JourneyStep"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/journey/steps/{stepId}":{"patch":{"operationId":"updateStudioJourneyStep","summary":"Update a studio journey step","description":"Check in, Check out, Complete and Collect balance accept timing only. Collect balance runs at check-in (`mode: auto`, `anchor: step` — the Check in step, offset 0), before the session (`mode: auto`, `anchor: session_start`, `offsetMinutes` -86400 to -60), or manually (`mode: manual`); anything else is 400 on the field. Confirmation returns 405. A listing step whose anchor is later is 400 naming it; a studio step cannot count from a listing step. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/JourneyStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateJourneyStepBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/JourneyStep"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteStudioJourneyStep","summary":"Archive a studio journey step","description":"Soft-archive. Confirmation, Check in and Collect balance return 405. Bookings in flight keep their rows; `pendingBookings` is how many still have this step pending. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/JourneyStepIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RemoveJourneyStepResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/journey/order":{"put":{"operationId":"reorderStudioJourney","summary":"Reorder studio journey steps","description":"`stepIds` must name every live studio step exactly once. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderJourneyBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/JourneyStep"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/journey":{"get":{"operationId":"listListingJourney","summary":"List a listing's journey","description":"Studio steps with their off state, then this listing's own steps (`own`). Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingJourney"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/journey/steps":{"post":{"operationId":"createListingJourneyStep","summary":"Add a listing journey step","description":"Add a listing journey step Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJourneyStepBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/JourneyStep"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/journey/steps/{stepId}":{"patch":{"operationId":"updateListingJourneyStep","summary":"Update a listing journey step","description":"Update a listing journey step Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"},{"$ref":"#/components/parameters/JourneyStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateJourneyStepBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/JourneyStep"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteListingJourneyStep","summary":"Archive a listing journey step","description":"Archive a listing journey step Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"},{"$ref":"#/components/parameters/JourneyStepIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RemoveJourneyStepResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/journey/order":{"put":{"operationId":"reorderListingJourney","summary":"Reorder a listing's own journey steps","description":"Reorder a listing's own journey steps Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderJourneyBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/JourneyStep"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/journey/off/{stepId}":{"put":{"operationId":"setListingJourneyStepOff","summary":"Switch a studio step off for one listing","description":"One override row pointing at the studio step. Confirmation, Check in, Collect balance, Check out and Complete return 405. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"},{"$ref":"#/components/parameters/JourneyStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetJourneyStepOffBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingJourney"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/journey/timing/{stepId}":{"put":{"operationId":"setListingJourneyStepTiming","summary":"Retime the studio Check in, Collect balance, Check out or Complete for one listing","description":"Writes the listing's own timing (`mode` auto or manual, the studio step's anchors and limits; Complete takes no anchor — manual means the team completes each booking once everything else is done; Collect balance runs at check-in with `anchor: step`, before the session with `anchor: session_start` and `offsetMinutes` -86400 to -60, or manually); `{ mode: null }` goes back to the studio's. Any other step returns 405. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"},{"$ref":"#/components/parameters/JourneyStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetJourneyStepTimingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingJourney"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/journey/arrive-and-leave":{"get":{"operationId":"getStudioArriveAndLeave","summary":"Read the business's Arrive and leave","description":"Check in, Check out and Complete as one mode — automatic, manual_checkout or manual — and the timing of each automatic step. Requires feature `business.view`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ArriveAndLeave"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"setStudioArriveAndLeave","summary":"Set the business's Arrive and leave","description":"Writes the studio Check in and Check out (and Complete when given). Listings that follow the business follow it; bookings already made keep their timing. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetArriveAndLeaveBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ArriveAndLeave"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/journey/arrive-and-leave":{"get":{"operationId":"getListingArriveAndLeave","summary":"Read a listing's Arrive and leave","description":"The listing's mode and timings as they run, `own` when any is its own, and the business's. Requires feature `location.view`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingArriveAndLeave"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"setListingArriveAndLeave","summary":"Set a listing's Arrive and leave","description":"Each of Check in, Check out and Complete carries the listing's own timing only where it differs from the business's; `{ mode: null }` follows the business. New bookings only — timing is fixed when a booking confirms. Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetArriveAndLeaveBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingArriveAndLeave"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/offerings/{offeringId}/pieces":{"put":{"operationId":"setListingPieces","summary":"Turn a listing's Pieces on or off","description":"On adds the five pieces steps to the listing's journey — In the kiln, Ready for pickup (text), Pickup reminder 14 days after Ready, Last call 28 days after Ready, Picked up (finishes the booking) — and sets the pickup line; already-present steps are kept. Off archives the listing's pieces steps and the timers counting from them; bookings in flight keep theirs (build-plan/277 D14). Requires feature `catalog.manage`.","tags":["catalog"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OfferingIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetListingPiecesBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ListingPieces"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/steps":{"get":{"operationId":"listBookingJourney","summary":"List a booking's journey","description":"The checklist with status, due, done, actor, note, `doneCount` / `partySize`, and `next`. Collect balance is omitted when the booking has no later amount. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingJourney"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/steps/{bookingStepId}/mark":{"post":{"operationId":"markBookingJourneyStep","summary":"Mark a booking journey step","description":"Without `acknowledged: true` this returns the preview and writes nothing. `count` is a partial mark on a manual step of a party booking. Collect balance charges a card and is never marked — 409, `details.code` `charges_card`; it runs on its timer, by `…/run`, or by the booking's Collect balance. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"},{"$ref":"#/components/parameters/BookingStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkJourneyStepBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/JourneyStepActionPreview"},{"$ref":"#/components/schemas/JourneyStepActionResult"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/steps/{bookingStepId}/skip":{"post":{"operationId":"skipBookingJourneyStep","summary":"Skip a booking journey step","description":"Skip a booking journey step Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"},{"$ref":"#/components/parameters/BookingStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkJourneyStepBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/JourneyStepActionPreview"},{"$ref":"#/components/schemas/JourneyStepActionResult"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/steps/{bookingStepId}/run":{"post":{"operationId":"runBookingJourneyStep","summary":"Run a booking journey step now","description":"Mark on an automatic pending step — and on Collect balance, automatic or manual, the one step verb that charges its card. On a sent message step, sends again with n+1. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"},{"$ref":"#/components/parameters/BookingStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkJourneyStepBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/JourneyStepActionPreview"},{"$ref":"#/components/schemas/JourneyStepActionResult"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/steps/{stepId}/mark":{"post":{"operationId":"markOccurrenceJourneyStep","summary":"Mark a journey step for everyone on a date","description":"Marks every live booking still pending at the step. `alreadyThere` is first names already past it. Preview when unacknowledged. Collect balance is refused (409, `details.code` `charges_card`): a date of cards is never charged at once. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"},{"$ref":"#/components/parameters/JourneyStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkJourneyStepBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/JourneyOccurrenceMarkPreview"},{"$ref":"#/components/schemas/JourneyOccurrenceMarkResult"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/steps/{bookingStepId}/message":{"get":{"operationId":"getBookingStepMessage","summary":"The message a booking step would send","description":"Rendered now for this customer. Nothing is sent. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"},{"$ref":"#/components/parameters/BookingStepIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"type":"object","properties":{"channel":{"anyOf":[{"type":"string","enum":["email","sms"]},{"type":"null"}]},"to":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"object","properties":{"subject":{"type":"string"},"html":{"type":"string"},"text":{"type":"string"}},"required":["subject","html","text"],"additionalProperties":false},"sms":{"anyOf":[{"type":"object","properties":{"body":{"type":"string"},"mediaUrls":{"description":"The Ready text's MMS photo (build-plan/277 D11).","type":"array","items":{"type":"string"}}},"required":["body"],"additionalProperties":false},{"type":"null"}]}},"required":["channel","to","email","sms"],"additionalProperties":false},{"type":"null"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/steps/{bookingStepId}/resend":{"post":{"operationId":"resendBookingStep","summary":"Send a booking step’s message again","description":"`to` corrects the customer’s email first. The step’s send count goes up by one. Requires feature `booking.checkin`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"},{"$ref":"#/components/parameters/BookingStepIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"step":{"$ref":"#/components/schemas/BookingStep"}},"required":["step"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/journey/preview":{"post":{"operationId":"previewJourneyMessage","summary":"Preview a journey message over a sample booking","description":"Preview a journey message over a sample booking Requires feature `business.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"stepName":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"},"channel":{"type":"string","enum":["email","sms"]},"offeringId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["stepName","subject","body","channel"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"channel":{"anyOf":[{"type":"string","enum":["email","sms"]},{"type":"null"}]},"to":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"object","properties":{"subject":{"type":"string"},"html":{"type":"string"},"text":{"type":"string"}},"required":["subject","html","text"],"additionalProperties":false},"sms":{"anyOf":[{"type":"object","properties":{"body":{"type":"string"},"mediaUrls":{"description":"The Ready text's MMS photo (build-plan/277 D11).","type":"array","items":{"type":"string"}}},"required":["body"],"additionalProperties":false},{"type":"null"}]}},"required":["channel","to","email","sms"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/performance":{"get":{"operationId":"getPerformanceIndex","summary":"Every visible report, drawn for the Overview","description":"The Overview in one request: every report the caller may see, with its metadata (including `panel`, how it is drawn), its rows and totals (capped like the report), and one headline sentence for the period. Unless `compare=off`, each report also carries `comparison` — the same definition's totals and headline over the comparison period, at the same location — and the top-level `comparison` names those dates. `trend` is the Sales definition's totals per day for a period of 31 days or fewer, else per Monday–Sunday week (the first and last clipped), over the period and, bucketed the same way, the comparison period; it is null when the caller cannot see Sales. A preset beginning `this_` runs to today and is compared with the same span of the unit before it. A report whose `ask` views the caller cannot read is omitted, never refused. Requires feature `reports.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}},{"in":"query","name":"compare","schema":{"description":"`previous` (the default — also for anything unrecognised): for a `this_*` preset, the same elapsed span of the unit before (October 1–11 → September 1–11, clipped to that unit); for a whole month, quarter, year or Monday–Sunday week — a `last_*` preset, or dates that span one — the whole unit before; otherwise the same number of days just before. `year`: the same dates a year earlier. `off`: no comparison.","type":"string","enum":["previous","year","off"]},"description":"`previous` (the default — also for anything unrecognised): for a `this_*` preset, the same elapsed span of the unit before (October 1–11 → September 1–11, clipped to that unit); for a whole month, quarter, year or Monday–Sunday week — a `last_*` preset, or dates that span one — the whole unit before; otherwise the same number of days just before. `year`: the same dates a year earlier. `off`: no comparison."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"timezone":{"type":"string"}},"required":["from","to","timezone"],"additionalProperties":false},"location":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"comparison":{"anyOf":[{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}]},"reports":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"group":{"type":"string","enum":["schedule","people","customers","sales"]},"title":{"type":"string"},"decision":{"type":"string"},"basis":{"type":"string","enum":["ran_in_period","cash","booked_in_period","as_of_period_end"]},"note":{"type":"string"},"module":{"type":"string"},"columns":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"type":{"type":"string","enum":["text","count","minutes","date","money","pct","ratio"]},"hidden":{"type":"boolean"},"labels":{"type":"string","enum":["accounting_category"]},"of":{"type":"string"},"over":{"type":"string"},"unit":{"type":"string","enum":["money","number"]}},"required":["name","label","type"],"additionalProperties":false}},"bar":{"type":"string"},"grid":{"type":"object","properties":{"x":{"type":"string"},"y":{"type":"string"},"value":{"type":"string"}},"required":["x","y","value"],"additionalProperties":false},"sort":{"type":"object","properties":{"column":{"type":"string"},"dir":{"type":"string","enum":["asc","desc"]}},"required":["column","dir"],"additionalProperties":false},"drill":{"type":"object","properties":{"path":{"type":"string"},"query":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["path","query"],"additionalProperties":false},"panel":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"bars"},"label":{"type":"string"},"value":{"type":"string"},"max":{"anyOf":[{"type":"number","const":100},{"type":"string","const":"auto"}]},"hue":{"type":"string","enum":["ink","red","clay","amber","olive","green","teal","cyan","blue","indigo","plum","pink"],"description":"A key of the listing colour picker’s presets — the panel’s one hue."}},"required":["kind","label","value","max","hue"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"grid"},"hue":{"type":"string","enum":["ink","red","clay","amber","olive","green","teal","cyan","blue","indigo","plum","pink"],"description":"A key of the listing colour picker’s presets — the panel’s one hue."}},"required":["kind","hue"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"stack"},"label":{"type":"string"},"a":{"type":"string"},"b":{"type":"string"},"aLabel":{"type":"string"},"bLabel":{"type":"string"},"hue":{"type":"string","enum":["ink","red","clay","amber","olive","green","teal","cyan","blue","indigo","plum","pink"],"description":"A key of the listing colour picker’s presets — the panel’s one hue."}},"required":["kind","label","a","b","aLabel","bLabel","hue"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"categories"},"by":{"type":"string"},"value":{"type":"string"},"item":{"type":"string"},"units":{"type":"string"}},"required":["kind","by","value","item","units"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"table"},"columns":{"type":"array","items":{"type":"string"}}},"required":["kind","columns"],"additionalProperties":false}],"type":"object"},"headline":{"anyOf":[{"type":"string"},{"type":"null"}]},"rowCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"truncated":{"type":"boolean"},"rows":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"totals":{"type":"array","items":{"type":"object","properties":{"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]}}},"required":["currency","values"],"additionalProperties":false}},"comparison":{"anyOf":[{"type":"object","properties":{"totals":{"type":"array","items":{"type":"object","properties":{"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]}}},"required":["currency","values"],"additionalProperties":false}},"headline":{"anyOf":[{"type":"string"},{"type":"null"}]},"rows":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["totals","headline","rows"],"additionalProperties":false},{"type":"null"}]}},"required":["id","group","title","decision","basis","columns","sort","headline","rowCount","truncated","rows","totals","comparison"],"additionalProperties":false}},"trend":{"anyOf":[{"type":"object","properties":{"report":{"type":"string","const":"sales"},"value":{"type":"string","const":"net"},"bucket":{"type":"string","enum":["day","week"]},"points":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"totals":{"type":"array","items":{"type":"object","properties":{"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]}}},"required":["currency","values"],"additionalProperties":false}}},"required":["from","to","totals"],"additionalProperties":false}},"comparison":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"totals":{"type":"array","items":{"type":"object","properties":{"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]}}},"required":["currency","values"],"additionalProperties":false}}},"required":["from","to","totals"],"additionalProperties":false}},{"type":"null"}]}},"required":["report","value","bucket","points","comparison"],"additionalProperties":false},{"type":"null"}]}},"required":["period","location","comparison","reports","trend"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/performance/{report}":{"get":{"operationId":"getPerformanceReport","summary":"One report for a period","description":"One report: its rows, its totals (money per currency, percentages recomputed from the summed parts), and its headline. An unknown or invisible report is a 404. `locationId` is ignored for a caller whose access is pinned to a location — theirs wins. Requires feature `reports.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PerformanceReportParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"report":{"type":"object","properties":{"id":{"type":"string"},"group":{"type":"string","enum":["schedule","people","customers","sales"]},"title":{"type":"string"},"decision":{"type":"string"},"basis":{"type":"string","enum":["ran_in_period","cash","booked_in_period","as_of_period_end"]},"note":{"type":"string"},"module":{"type":"string"},"columns":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"type":{"type":"string","enum":["text","count","minutes","date","money","pct","ratio"]},"hidden":{"type":"boolean"},"labels":{"type":"string","enum":["accounting_category"]},"of":{"type":"string"},"over":{"type":"string"},"unit":{"type":"string","enum":["money","number"]}},"required":["name","label","type"],"additionalProperties":false}},"bar":{"type":"string"},"grid":{"type":"object","properties":{"x":{"type":"string"},"y":{"type":"string"},"value":{"type":"string"}},"required":["x","y","value"],"additionalProperties":false},"sort":{"type":"object","properties":{"column":{"type":"string"},"dir":{"type":"string","enum":["asc","desc"]}},"required":["column","dir"],"additionalProperties":false},"drill":{"type":"object","properties":{"path":{"type":"string"},"query":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["path","query"],"additionalProperties":false},"panel":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"bars"},"label":{"type":"string"},"value":{"type":"string"},"max":{"anyOf":[{"type":"number","const":100},{"type":"string","const":"auto"}]},"hue":{"type":"string","enum":["ink","red","clay","amber","olive","green","teal","cyan","blue","indigo","plum","pink"],"description":"A key of the listing colour picker’s presets — the panel’s one hue."}},"required":["kind","label","value","max","hue"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"grid"},"hue":{"type":"string","enum":["ink","red","clay","amber","olive","green","teal","cyan","blue","indigo","plum","pink"],"description":"A key of the listing colour picker’s presets — the panel’s one hue."}},"required":["kind","hue"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"stack"},"label":{"type":"string"},"a":{"type":"string"},"b":{"type":"string"},"aLabel":{"type":"string"},"bLabel":{"type":"string"},"hue":{"type":"string","enum":["ink","red","clay","amber","olive","green","teal","cyan","blue","indigo","plum","pink"],"description":"A key of the listing colour picker’s presets — the panel’s one hue."}},"required":["kind","label","a","b","aLabel","bLabel","hue"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"categories"},"by":{"type":"string"},"value":{"type":"string"},"item":{"type":"string"},"units":{"type":"string"}},"required":["kind","by","value","item","units"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"table"},"columns":{"type":"array","items":{"type":"string"}}},"required":["kind","columns"],"additionalProperties":false}],"type":"object"}},"required":["id","group","title","decision","basis","columns","sort"],"additionalProperties":false},"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"timezone":{"type":"string"},"basis":{"type":"string","enum":["ran_in_period","cash","booked_in_period","as_of_period_end"]}},"required":["from","to","timezone","basis"],"additionalProperties":false},"location":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"type":{"type":"string","enum":["text","count","minutes","date","money","pct","ratio"]},"hidden":{"type":"boolean"},"labels":{"type":"string","enum":["accounting_category"]},"of":{"type":"string"},"over":{"type":"string"},"unit":{"type":"string","enum":["money","number"]}},"required":["name","label","type"],"additionalProperties":false}},"rows":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"totals":{"type":"array","items":{"type":"object","properties":{"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]}}},"required":["currency","values"],"additionalProperties":false}},"headline":{"anyOf":[{"type":"string"},{"type":"null"}]},"truncated":{"type":"boolean"}},"required":["report","period","location","columns","rows","totals","headline","truncated"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/performance/{report}/export":{"get":{"operationId":"exportPerformanceCsv","summary":"Export one report as CSV","description":"The same rows as a CSV download, capped like the page. Filename is `performance-{report}-{from}-{to}.csv`. A report that reads a finance view also needs `finance.export`. Requires feature `reports.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PerformanceReportParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"CSV file contents","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/pieces":{"get":{"operationId":"listBookingPieces","summary":"List a booking's pieces","description":"The live pieces on the booking in their order, with signed photo links good for an hour; `slots`, its required add-ons still waiting for a piece; the names its listing gives the stages; the pickup line; and the location's shelves. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BookingPieces"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"addBookingPiece","summary":"Add a piece to a booking","description":"A new piece at Made, with 0–5 photos as multipart `photos[]` (zero is a piece without a picture; JSON works then too). With `orderLineId` it fills one of the booking's required add-ons and, without a `label`, takes its name. Refused on a booking that is held, canceled or a no-show. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/AddPieceBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Piece"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/occurrences/{occurrenceId}/pieces":{"get":{"operationId":"listOccurrencePieces","summary":"List a class date's pieces","description":"The class board's pieces and the camera's session: every booking on the date that can hold them — who it is, its spots, its reference, its required add-ons still waiting — each with its live pieces (signed photo links good for an hour), in one read, with the listing and its start and end on the location's clock. The date tracks pieces when its listing has Pieces on or any booking on it has a piece; otherwise `bookings` is empty. A party with none yet is listed with an empty `pieces`. An instructor reaches the dates they teach. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OccurrenceIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OccurrencePieces"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/bookings/{bookingId}/pieces/remind":{"post":{"operationId":"remindBookingPieces","summary":"Send a booking's pickup reminder now","description":"*Remind* on the shelf's Ready group: runs the booking's first pending automatic message step that counts from its Ready step (the pickup reminder, then the last call) now, through Run now. A 409 when the booking has none left. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PieceReminder"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pieces":{"get":{"operationId":"listPieceShelf","summary":"List the shelf","description":"Bookings → Pickups for pieces: one stage at a location, grouped by booking. Made, In the kiln and Ready list the longest-waiting group first, unpaged; Picked up is newest first, 25 bookings a page. `shelf` narrows to one shelf, `q` searches the customer, the booking reference and the piece's name. It carries what the location keeps — its shelves, its stage words, whether it tracks pieces. An instructor gets an empty shelf. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"stage","schema":{"description":"Default `ready`.","type":"string","enum":["made","in_kiln","ready","picked_up"]},"description":"Default `ready`."},{"in":"query","name":"shelf","schema":{"type":"string"}},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"cursor","schema":{"description":"Picked up only: the previous page's `nextCursor`.","type":"string"},"description":"Picked up only: the previous page's `nextCursor`."},{"in":"query","name":"limit","schema":{"description":"Picked up only: bookings a page, default 25, at most 100.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"description":"Picked up only: bookings a page, default 25, at most 100."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PieceShelf"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pieces/move":{"post":{"operationId":"movePieces","summary":"Move pieces to a stage","description":"Moves pieces forward (Made → In the kiln → Ready → Picked up, Made → Ready, Ready → Not collected) or back one stage, one transaction per booking. A piece already at the stage is left as it is; a move the rules refuse is a 409 and nothing moves. In the kiln clears the shelf. With `preview` it returns `{ sentence, pieces, bookings, notify }` and moves nothing; otherwise `{ moved, undoUntil }`. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PieceMoveBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/PieceMovePreview"},{"$ref":"#/components/schemas/PieceMoveResult"}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pieces/{pieceId}":{"patch":{"operationId":"updatePiece","summary":"Rename a piece or set its shelf","description":"A shelf must be one of the location's where it keeps them; where it keeps none it is any short text. A piece in the kiln takes no shelf. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PieceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePieceBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Piece"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"removePiece","summary":"Remove a piece","description":"Takes the piece off its booking and out of every count. Its photos are kept for now. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PieceIdParam"}],"responses":{"204":{"description":"Removed"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pieces/{pieceId}/booking":{"post":{"operationId":"movePieceToBooking","summary":"Move a piece to another booking","description":"*Move to…*: a piece logged under the wrong name goes to the booking it belongs to. Only a piece at Made, to another booking of the business that holds pieces. It keeps its photos, name and stage, goes to the end of that booking's pieces, and leaves its add-on behind — an add-on stays with the booking that bought it. Both bookings record `booking.piece_moved_to`. A 409 past Made, to the same booking, or to a booking that is held, canceled or a no-show; 404 for a booking not in the business. An instructor with the permission reaches only their own classes, both ends. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PieceIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MovePieceToBookingBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Piece"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pieces/{pieceId}/photos":{"post":{"operationId":"addPiecePhotos","summary":"Add photos to a piece","description":"Another side — the signed bottom. Multipart `photos[]`; at most five on the piece in all (a piece that already has more keeps them). With `replacePhotoId` it is a retake: one photo takes that photo's place and the old one is deleted. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PieceIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/AddPiecePhotosBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Piece"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/pieces/{pieceId}/photos/{photoId}":{"delete":{"operationId":"deletePiecePhoto","summary":"Delete a photo of a piece","description":"The photo is gone for good; the next one becomes the cover. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PieceIdParam"},{"$ref":"#/components/parameters/PiecePhotoIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Piece"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/inline-ai/name-piece":{"post":{"operationId":"namePieceInline","summary":"Name a piece from its photo","description":"A one- or two-word name read from the piece's cover photo — *Giraffe*, *Mug* — kept as a suggestion only while the piece has no name. A name a person typed is never replaced: the piece's own comes back unchanged. One model call, under the inline AI limit and the business's daily allowance. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NamePieceBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PieceName"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/locations/{locationId}/piece-shelves":{"get":{"operationId":"getPieceShelves","summary":"Get a location's shelves","description":"The business's own shelf IDs at this location — A1, A2, B1 — in its order. Empty when it keeps none. Requires feature `booking.view`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PieceShelvesOutput"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"setPieceShelves","summary":"Set a location's shelves","description":"The whole list, in order. Blanks are dropped; each is at most 12 characters and listed once (A1 and a1 are one shelf). A piece keeps a shelf that left the list. Requires feature `booking.manage`.","tags":["booking"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/LocationIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PieceShelves"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PieceShelvesOutput"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/memberships/report":{"get":{"operationId":"getMembershipDailyReport","summary":"The daily membership report, as facts","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. The heartbeat for the renewal (build-plan/265 D15; architecture/05 § The daily report): the counts, the problems, one line per business and tomorrow, read now from the events, the task table, the payments and the deliveries. Demo businesses are left out. Reading sweeps nothing.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"query","name":"date","schema":{"description":"The day, YYYY-MM-DD (UTC); today when left out. The report covers the 24 hours to 13:00 UTC that day.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"The day, YYYY-MM-DD (UTC); today when left out. The report covers the 24 hours to 13:00 UTC that day."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"date":{"type":"string","description":"The report’s day, UTC (YYYY-MM-DD)"},"dayLabel":{"type":"string"},"from":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"to":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"generatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"environment":{"type":"string"},"counts":{"type":"object","properties":{"due":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"charged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"chargedAmount":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Minor units by currency code"},"declined":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"recovered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"ended":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"canceledAtPeriodEnd":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paused":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cardsUpdated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"pending":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"subscriptions":{"type":"object","properties":{"due":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"charged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"declined":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"ended":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"canceledAtPeriodEnd":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["due","charged","declined","ended","canceledAtPeriodEnd","created"],"additionalProperties":false,"description":"How many of the counts above were subscriptions — memberships on a listing’s plan (build-plan/280)"}},"required":["due","charged","chargedAmount","declined","recovered","ended","canceledAtPeriodEnd","paused","created","cardsUpdated","pending","subscriptions"],"additionalProperties":false},"problems":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["renewal_task_failed","payment_pending","swept","renewal_not_scheduled","mail_failed","session_unavailable"]},"membershipId":{"$ref":"#/components/schemas/Uuid"},"planName":{"type":"string"},"businessName":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"detail":{"type":"string"}},"required":["kind","membershipId","planName","businessName","at","detail"],"additionalProperties":false}},"businesses":{"type":"array","items":{"type":"object","properties":{"businessId":{"$ref":"#/components/schemas/Uuid"},"businessName":{"type":"string"},"due":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"charged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"chargedAmount":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Minor units by currency code"},"declined":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["businessId","businessName","due","charged","chargedAmount","declined"],"additionalProperties":false}},"tomorrow":{"type":"object","properties":{"due":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Minor units by currency code"}},"required":["due","amount"],"additionalProperties":false},"swept":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["date","dayLabel","from","to","generatedAt","environment","counts","problems","businesses","tomorrow","swept"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/memberships/report/send":{"post":{"operationId":"sendMembershipDailyReport","summary":"Send a day’s membership report again","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. Runs the renewal sweep, then mails the day’s report to every platform admin without waiting for 13:00 UTC. Meant to arrive: it carries its own idempotency key, unlike the scheduled send.","tags":["system"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"description":"The day, YYYY-MM-DD (UTC); today when left out. The report covers the 24 hours to 13:00 UTC that day.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"date":{"type":"string"},"subject":{"type":"string"},"sent":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"recipients":{"type":"array","items":{"type":"string"}}},"required":["date","subject","sent","recipients"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/overview":{"get":{"operationId":"getPlatformOverview","summary":"Every live location, and who is waiting to join","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"generatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"totals":{"type":"object","properties":{"businesses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"locations":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"live":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingsLast30Days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingsNext7Days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"collectedLast30Days":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["currency","amount"],"additionalProperties":false}},"waiting":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"signupWaitlist":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"trxWatching":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["businesses","locations","live","bookingsLast30Days","bookingsNext7Days","collectedLast30Days","waiting","signupWaitlist","trxWatching"],"additionalProperties":false},"locations":{"type":"array","items":{"type":"object","properties":{"businessId":{"$ref":"#/components/schemas/Uuid"},"businessName":{"type":"string"},"businessSlug":{"type":"string"},"businessType":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessCreatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"locationId":{"$ref":"#/components/schemas/Uuid"},"locationName":{"type":"string"},"locationSlug":{"type":"string"},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"timezone":{"type":"string"},"status":{"type":"string","enum":["live","cardsOff","paused","setup"]},"chargesEnabled":{"type":"boolean"},"stripeOnboardingStatus":{"type":"string"},"bookingPaused":{"type":"boolean"},"owners":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false}},"publishedListings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"customers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingsLast30Days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingsNext7Days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"collectedLast30Days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"waiting":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastBookedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"trx":{"anyOf":[{"type":"object","properties":{"saleUnbatched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"batchUnsettled":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"batchUnreconciled":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"returnUnconfirmed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["saleUnbatched","batchUnsettled","batchUnreconciled","returnUnconfirmed"],"additionalProperties":false},{"type":"null"}]}},"required":["businessId","businessName","businessSlug","businessType","businessCreatedAt","locationId","locationName","locationSlug","city","region","timezone","status","chargesEnabled","stripeOnboardingStatus","bookingPaused","owners","publishedListings","customers","bookingsLast30Days","bookingsNext7Days","collectedLast30Days","currency","waiting","lastBookedAt","trx"],"additionalProperties":false}},"signupWaitlist":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"studio":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"hasAccount":{"type":"boolean"},"invited":{"type":"boolean"}},"required":["email","studio","source","createdAt","hasAccount","invited"],"additionalProperties":false}}},"required":["generatedAt","totals","locations","signupWaitlist"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/legacy-mirrors":{"get":{"operationId":"listLegacyMirrors","summary":"Legacy mirrors","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. Accounts that have no business yet are on this list.","tags":["system"],"security":[{"sessionBearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"legacyAccountRef":{"type":"string"},"legacyAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["waiting","running","mirroring","stopped","live"]},"enabled":{"type":"boolean"},"enabledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"cutoverAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastResult":{"anyOf":[{"type":"object","properties":{"ranAt":{"type":"string"},"catalog":{"type":"object","properties":{"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"archived":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"takenOver":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"followed":{"type":"boolean"}},"required":["created","updated","unchanged","archived","takenOver","failed","followed"],"additionalProperties":false},"claims":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"synced":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"moved":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"released":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unmatched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["bookings","synced","created","moved","updated","released","unchanged","unmatched"],"additionalProperties":false}},"required":["ranAt","catalog","claims"],"additionalProperties":false},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","legacyAccountRef","legacyAccountId","businessId","businessName","businessSlug","locationId","locationSlug","state","enabled","enabledAt","cutoverAt","nextRunAt","lastRunAt","lastResult","lastError","createdAt"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createLegacyMirror","summary":"Start a legacy mirror","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"legacyAccountRef":{"type":"string"}},"required":["legacyAccountRef"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"legacyAccountRef":{"type":"string"},"legacyAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["waiting","running","mirroring","stopped","live"]},"enabled":{"type":"boolean"},"enabledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"cutoverAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastResult":{"anyOf":[{"type":"object","properties":{"ranAt":{"type":"string"},"catalog":{"type":"object","properties":{"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"archived":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"takenOver":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"followed":{"type":"boolean"}},"required":["created","updated","unchanged","archived","takenOver","failed","followed"],"additionalProperties":false},"claims":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"synced":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"moved":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"released":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unmatched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["bookings","synced","created","moved","updated","released","unchanged","unmatched"],"additionalProperties":false}},"required":["ranAt","catalog","claims"],"additionalProperties":false},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","legacyAccountRef","legacyAccountId","businessId","businessName","businessSlug","locationId","locationSlug","state","enabled","enabledAt","cutoverAt","nextRunAt","lastRunAt","lastResult","lastError","createdAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/legacy-mirrors/{mirrorId}/run":{"post":{"operationId":"runLegacyMirror","summary":"Run a legacy mirror now","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/LegacyMirrorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"legacyAccountRef":{"type":"string"},"legacyAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["waiting","running","mirroring","stopped","live"]},"enabled":{"type":"boolean"},"enabledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"cutoverAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastResult":{"anyOf":[{"type":"object","properties":{"ranAt":{"type":"string"},"catalog":{"type":"object","properties":{"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"archived":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"takenOver":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"followed":{"type":"boolean"}},"required":["created","updated","unchanged","archived","takenOver","failed","followed"],"additionalProperties":false},"claims":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"synced":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"moved":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"released":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unmatched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["bookings","synced","created","moved","updated","released","unchanged","unmatched"],"additionalProperties":false}},"required":["ranAt","catalog","claims"],"additionalProperties":false},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","legacyAccountRef","legacyAccountId","businessId","businessName","businessSlug","locationId","locationSlug","state","enabled","enabledAt","cutoverAt","nextRunAt","lastRunAt","lastResult","lastError","createdAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/legacy-mirrors/{mirrorId}/stop":{"post":{"operationId":"stopLegacyMirror","summary":"Stop a legacy mirror","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/LegacyMirrorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"legacyAccountRef":{"type":"string"},"legacyAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["waiting","running","mirroring","stopped","live"]},"enabled":{"type":"boolean"},"enabledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"cutoverAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastResult":{"anyOf":[{"type":"object","properties":{"ranAt":{"type":"string"},"catalog":{"type":"object","properties":{"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"archived":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"takenOver":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"followed":{"type":"boolean"}},"required":["created","updated","unchanged","archived","takenOver","failed","followed"],"additionalProperties":false},"claims":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"synced":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"moved":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"released":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unmatched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["bookings","synced","created","moved","updated","released","unchanged","unmatched"],"additionalProperties":false}},"required":["ranAt","catalog","claims"],"additionalProperties":false},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","legacyAccountRef","legacyAccountId","businessId","businessName","businessSlug","locationId","locationSlug","state","enabled","enabledAt","cutoverAt","nextRunAt","lastRunAt","lastResult","lastError","createdAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/legacy-mirrors/{mirrorId}/start":{"post":{"operationId":"startLegacyMirror","summary":"Start a stopped legacy mirror","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/LegacyMirrorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"legacyAccountRef":{"type":"string"},"legacyAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["waiting","running","mirroring","stopped","live"]},"enabled":{"type":"boolean"},"enabledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"cutoverAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastResult":{"anyOf":[{"type":"object","properties":{"ranAt":{"type":"string"},"catalog":{"type":"object","properties":{"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"archived":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"takenOver":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"followed":{"type":"boolean"}},"required":["created","updated","unchanged","archived","takenOver","failed","followed"],"additionalProperties":false},"claims":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"synced":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"moved":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"released":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unmatched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["bookings","synced","created","moved","updated","released","unchanged","unmatched"],"additionalProperties":false}},"required":["ranAt","catalog","claims"],"additionalProperties":false},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","legacyAccountRef","legacyAccountId","businessId","businessName","businessSlug","locationId","locationSlug","state","enabled","enabledAt","cutoverAt","nextRunAt","lastRunAt","lastResult","lastError","createdAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/legacy-mirrors/{mirrorId}/cutover":{"post":{"operationId":"cutOverLegacyMirror","summary":"Cut a legacy mirror over to live","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/LegacyMirrorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"legacyAccountRef":{"type":"string"},"legacyAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"businessSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["waiting","running","mirroring","stopped","live"]},"enabled":{"type":"boolean"},"enabledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"cutoverAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastRunAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastResult":{"anyOf":[{"type":"object","properties":{"ranAt":{"type":"string"},"catalog":{"type":"object","properties":{"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"archived":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"takenOver":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"followed":{"type":"boolean"}},"required":["created","updated","unchanged","archived","takenOver","failed","followed"],"additionalProperties":false},"claims":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"synced":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"moved":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"released":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unmatched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["bookings","synced","created","moved","updated","released","unchanged","unmatched"],"additionalProperties":false}},"required":["ranAt","catalog","claims"],"additionalProperties":false},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","legacyAccountRef","legacyAccountId","businessId","businessName","businessSlug","locationId","locationSlug","state","enabled","enabledAt","cutoverAt","nextRunAt","lastRunAt","lastResult","lastError","createdAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/legacy-mirrors/{mirrorId}/preview":{"post":{"operationId":"previewLegacyMirror","summary":"A short link to a mirror’s shadow page","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. Two hours, for the admin who asked.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/LegacyMirrorIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/calls":{"get":{"operationId":"listPhoneCalls","summary":"Calls to the support line","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"businessId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["ringing","answered","completed","missed","voicemail"]},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"answeredAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"durationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingKind":{"anyOf":[{"type":"string","enum":["call","voicemail"]},{"type":"null"}]},"recordingDurationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hasRecording":{"type":"boolean"},"transcribeState":{"anyOf":[{"type":"string","enum":["waiting","done","failed","skipped"]},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","answeredBy","startedAt","answeredAt","durationSec","recordingKind","recordingDurationSec","hasRecording","transcribeState","summary"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/calls/{callId}":{"get":{"operationId":"getPhoneCall","summary":"One call, with its transcript","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneCallIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["ringing","answered","completed","missed","voicemail"]},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"answeredAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"durationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingKind":{"anyOf":[{"type":"string","enum":["call","voicemail"]},{"type":"null"}]},"recordingDurationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hasRecording":{"type":"boolean"},"transcribeState":{"anyOf":[{"type":"string","enum":["waiting","done","failed","skipped"]},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}]},"transcribeError":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","answeredBy","startedAt","answeredAt","durationSec","recordingKind","recordingDurationSec","hasRecording","transcribeState","summary","transcript","transcribeError"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/calls/{callId}/recording":{"get":{"operationId":"getPhoneCallRecording","summary":"A call’s recording","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. The body is `audio/mpeg`, not a JSON envelope.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneCallIdParam"}],"responses":{"200":{"description":"MPEG audio"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/threads":{"get":{"operationId":"listPhoneThreads","summary":"Texts to the support line, one conversation per number","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"businessId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["new","taken","completed"]},"takenBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"completedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastBody":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastDirection":{"anyOf":[{"type":"string","enum":["in","out"]},{"type":"null"}]},"lastMediaCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","takenBy","completedBy","summary","lastAt","lastBody","lastDirection","lastMediaCount","messageCount"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/threads/{threadId}":{"get":{"operationId":"getPhoneThread","summary":"One text conversation, with its messages","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneThreadIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["new","taken","completed"]},"takenBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"completedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastBody":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastDirection":{"anyOf":[{"type":"string","enum":["in","out"]},{"type":"null"}]},"lastMediaCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"direction":{"type":"string","enum":["in","out"]},"body":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"sentBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"delivery":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"media":{"type":"array","items":{"type":"object","properties":{"contentType":{"type":"string"},"ready":{"type":"boolean"}},"required":["contentType","ready"],"additionalProperties":false}}},"required":["id","direction","body","at","sentBy","delivery","errorCode","media"],"additionalProperties":false}},"brief":{"anyOf":[{"type":"object","properties":{"asking":{"type":"string"},"facts":{"type":"array","items":{"type":"string"}},"reply":{"type":"string"},"needs":{"anyOf":[{"type":"string"},{"type":"null"}]},"help":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"heading":{"type":"string"},"line":{"type":"string"},"href":{"type":"string"}},"required":["slug","title","heading","line","href"],"additionalProperties":false}},"before":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["thread","call"]},"id":{"$ref":"#/components/schemas/Uuid"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"line":{"type":"string"}},"required":["kind","id","at","line"],"additionalProperties":false}},"model":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["asking","facts","reply","needs","help","before","model","at"],"additionalProperties":false},{"type":"null"}]},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["ringing","answered","completed","missed","voicemail"]},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"durationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingKind":{"anyOf":[{"type":"string","enum":["call","voicemail"]},{"type":"null"}]},"recordingDurationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hasRecording":{"type":"boolean"},"transcribeState":{"anyOf":[{"type":"string","enum":["waiting","done","failed","skipped"]},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","answeredBy","startedAt","durationSec","recordingKind","recordingDurationSec","hasRecording","transcribeState","summary","transcript"],"additionalProperties":false}},"context":{"type":"object","properties":{"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"bookings":{"type":"array","items":{"type":"object","properties":{"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"listing":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"status":{"type":"string"},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paid":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refunded":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["reference","listing","startsAt","status","total","paid","refunded","currency"],"additionalProperties":false}}},"required":["businessName","locationName","matchKind","bookings"],"additionalProperties":false},"canReply":{"type":"boolean"}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","takenBy","completedBy","summary","lastAt","lastBody","lastDirection","lastMediaCount","messageCount","messages","brief","calls","context","canReply"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/threads/{threadId}/take":{"post":{"operationId":"takePhoneThread","summary":"Take a text conversation","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneThreadIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["new","taken","completed"]},"takenBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"completedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastBody":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastDirection":{"anyOf":[{"type":"string","enum":["in","out"]},{"type":"null"}]},"lastMediaCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"direction":{"type":"string","enum":["in","out"]},"body":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"sentBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"delivery":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"media":{"type":"array","items":{"type":"object","properties":{"contentType":{"type":"string"},"ready":{"type":"boolean"}},"required":["contentType","ready"],"additionalProperties":false}}},"required":["id","direction","body","at","sentBy","delivery","errorCode","media"],"additionalProperties":false}},"brief":{"anyOf":[{"type":"object","properties":{"asking":{"type":"string"},"facts":{"type":"array","items":{"type":"string"}},"reply":{"type":"string"},"needs":{"anyOf":[{"type":"string"},{"type":"null"}]},"help":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"heading":{"type":"string"},"line":{"type":"string"},"href":{"type":"string"}},"required":["slug","title","heading","line","href"],"additionalProperties":false}},"before":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["thread","call"]},"id":{"$ref":"#/components/schemas/Uuid"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"line":{"type":"string"}},"required":["kind","id","at","line"],"additionalProperties":false}},"model":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["asking","facts","reply","needs","help","before","model","at"],"additionalProperties":false},{"type":"null"}]},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["ringing","answered","completed","missed","voicemail"]},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"durationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingKind":{"anyOf":[{"type":"string","enum":["call","voicemail"]},{"type":"null"}]},"recordingDurationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hasRecording":{"type":"boolean"},"transcribeState":{"anyOf":[{"type":"string","enum":["waiting","done","failed","skipped"]},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","answeredBy","startedAt","durationSec","recordingKind","recordingDurationSec","hasRecording","transcribeState","summary","transcript"],"additionalProperties":false}},"context":{"type":"object","properties":{"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"bookings":{"type":"array","items":{"type":"object","properties":{"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"listing":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"status":{"type":"string"},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paid":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refunded":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["reference","listing","startsAt","status","total","paid","refunded","currency"],"additionalProperties":false}}},"required":["businessName","locationName","matchKind","bookings"],"additionalProperties":false},"canReply":{"type":"boolean"}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","takenBy","completedBy","summary","lastAt","lastBody","lastDirection","lastMediaCount","messageCount","messages","brief","calls","context","canReply"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/threads/{threadId}/messages":{"post":{"operationId":"replyToPhoneThread","summary":"Reply in a text conversation","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. Multipart: `body` is the reply, `file` is an optional photo.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneThreadIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"body":{"type":"string"},"file":{"description":"A photo","type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["new","taken","completed"]},"takenBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"completedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastBody":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastDirection":{"anyOf":[{"type":"string","enum":["in","out"]},{"type":"null"}]},"lastMediaCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"direction":{"type":"string","enum":["in","out"]},"body":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"sentBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"delivery":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"media":{"type":"array","items":{"type":"object","properties":{"contentType":{"type":"string"},"ready":{"type":"boolean"}},"required":["contentType","ready"],"additionalProperties":false}}},"required":["id","direction","body","at","sentBy","delivery","errorCode","media"],"additionalProperties":false}},"brief":{"anyOf":[{"type":"object","properties":{"asking":{"type":"string"},"facts":{"type":"array","items":{"type":"string"}},"reply":{"type":"string"},"needs":{"anyOf":[{"type":"string"},{"type":"null"}]},"help":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"heading":{"type":"string"},"line":{"type":"string"},"href":{"type":"string"}},"required":["slug","title","heading","line","href"],"additionalProperties":false}},"before":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["thread","call"]},"id":{"$ref":"#/components/schemas/Uuid"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"line":{"type":"string"}},"required":["kind","id","at","line"],"additionalProperties":false}},"model":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["asking","facts","reply","needs","help","before","model","at"],"additionalProperties":false},{"type":"null"}]},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["ringing","answered","completed","missed","voicemail"]},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"durationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingKind":{"anyOf":[{"type":"string","enum":["call","voicemail"]},{"type":"null"}]},"recordingDurationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hasRecording":{"type":"boolean"},"transcribeState":{"anyOf":[{"type":"string","enum":["waiting","done","failed","skipped"]},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","answeredBy","startedAt","durationSec","recordingKind","recordingDurationSec","hasRecording","transcribeState","summary","transcript"],"additionalProperties":false}},"context":{"type":"object","properties":{"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"bookings":{"type":"array","items":{"type":"object","properties":{"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"listing":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"status":{"type":"string"},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paid":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refunded":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["reference","listing","startsAt","status","total","paid","refunded","currency"],"additionalProperties":false}}},"required":["businessName","locationName","matchKind","bookings"],"additionalProperties":false},"canReply":{"type":"boolean"}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","takenBy","completedBy","summary","lastAt","lastBody","lastDirection","lastMediaCount","messageCount","messages","brief","calls","context","canReply"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/threads/{threadId}/complete":{"post":{"operationId":"completePhoneThread","summary":"Complete a text conversation","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneThreadIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["new","taken","completed"]},"takenBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"completedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastBody":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastDirection":{"anyOf":[{"type":"string","enum":["in","out"]},{"type":"null"}]},"lastMediaCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"direction":{"type":"string","enum":["in","out"]},"body":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"sentBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"delivery":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"media":{"type":"array","items":{"type":"object","properties":{"contentType":{"type":"string"},"ready":{"type":"boolean"}},"required":["contentType","ready"],"additionalProperties":false}}},"required":["id","direction","body","at","sentBy","delivery","errorCode","media"],"additionalProperties":false}},"brief":{"anyOf":[{"type":"object","properties":{"asking":{"type":"string"},"facts":{"type":"array","items":{"type":"string"}},"reply":{"type":"string"},"needs":{"anyOf":[{"type":"string"},{"type":"null"}]},"help":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"heading":{"type":"string"},"line":{"type":"string"},"href":{"type":"string"}},"required":["slug","title","heading","line","href"],"additionalProperties":false}},"before":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["thread","call"]},"id":{"$ref":"#/components/schemas/Uuid"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"line":{"type":"string"}},"required":["kind","id","at","line"],"additionalProperties":false}},"model":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["asking","facts","reply","needs","help","before","model","at"],"additionalProperties":false},{"type":"null"}]},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["ringing","answered","completed","missed","voicemail"]},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"durationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingKind":{"anyOf":[{"type":"string","enum":["call","voicemail"]},{"type":"null"}]},"recordingDurationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hasRecording":{"type":"boolean"},"transcribeState":{"anyOf":[{"type":"string","enum":["waiting","done","failed","skipped"]},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","answeredBy","startedAt","durationSec","recordingKind","recordingDurationSec","hasRecording","transcribeState","summary","transcript"],"additionalProperties":false}},"context":{"type":"object","properties":{"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"bookings":{"type":"array","items":{"type":"object","properties":{"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"listing":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"status":{"type":"string"},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paid":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refunded":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["reference","listing","startsAt","status","total","paid","refunded","currency"],"additionalProperties":false}}},"required":["businessName","locationName","matchKind","bookings"],"additionalProperties":false},"canReply":{"type":"boolean"}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","takenBy","completedBy","summary","lastAt","lastBody","lastDirection","lastMediaCount","messageCount","messages","brief","calls","context","canReply"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/threads/{threadId}/assign":{"post":{"operationId":"assignPhoneThread","summary":"Put an unknown number with a location","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneThreadIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"}},"required":["locationId"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"fromDisplay":{"type":"string"},"callerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"businessId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"status":{"type":"string","enum":["new","taken","completed"]},"takenBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"completedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastBody":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastDirection":{"anyOf":[{"type":"string","enum":["in","out"]},{"type":"null"}]},"lastMediaCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"direction":{"type":"string","enum":["in","out"]},"body":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"sentBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"delivery":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"media":{"type":"array","items":{"type":"object","properties":{"contentType":{"type":"string"},"ready":{"type":"boolean"}},"required":["contentType","ready"],"additionalProperties":false}}},"required":["id","direction","body","at","sentBy","delivery","errorCode","media"],"additionalProperties":false}},"brief":{"anyOf":[{"type":"object","properties":{"asking":{"type":"string"},"facts":{"type":"array","items":{"type":"string"}},"reply":{"type":"string"},"needs":{"anyOf":[{"type":"string"},{"type":"null"}]},"help":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"heading":{"type":"string"},"line":{"type":"string"},"href":{"type":"string"}},"required":["slug","title","heading","line","href"],"additionalProperties":false}},"before":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["thread","call"]},"id":{"$ref":"#/components/schemas/Uuid"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"line":{"type":"string"}},"required":["kind","id","at","line"],"additionalProperties":false}},"model":{"type":"string"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["asking","facts","reply","needs","help","before","model","at"],"additionalProperties":false},{"type":"null"}]},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["ringing","answered","completed","missed","voicemail"]},"answeredBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"durationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"recordingKind":{"anyOf":[{"type":"string","enum":["call","voicemail"]},{"type":"null"}]},"recordingDurationSec":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hasRecording":{"type":"boolean"},"transcribeState":{"anyOf":[{"type":"string","enum":["waiting","done","failed","skipped"]},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","status","answeredBy","startedAt","durationSec","recordingKind","recordingDurationSec","hasRecording","transcribeState","summary","transcript"],"additionalProperties":false}},"context":{"type":"object","properties":{"businessName":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"matchKind":{"anyOf":[{"type":"string","enum":["team","location","customer","assigned"]},{"type":"null"}]},"bookings":{"type":"array","items":{"type":"object","properties":{"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"listing":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"status":{"type":"string"},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paid":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refunded":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["reference","listing","startsAt","status","total","paid","refunded","currency"],"additionalProperties":false}}},"required":["businessName","locationName","matchKind","bookings"],"additionalProperties":false},"canReply":{"type":"boolean"}},"required":["id","from","fromDisplay","callerName","matchKind","businessId","businessName","locationId","locationName","customerId","status","takenBy","completedBy","summary","lastAt","lastBody","lastDirection","lastMediaCount","messageCount","messages","brief","calls","context","canReply"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/threads/{threadId}/draft":{"post":{"operationId":"draftPhoneReply","summary":"Draft a reply","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneThreadIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/texts/{textId}":{"get":{"operationId":"getPhoneText","summary":"The conversation a text belongs to","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. An old link names a text; this returns its thread.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneTextIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"threadId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["id","threadId"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/texts/{textId}/media/{index}":{"get":{"operationId":"getPhoneTextMedia","summary":"One photo from a text","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. The body is the stored image, not a JSON envelope.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/PhoneTextIdParam"},{"$ref":"#/components/parameters/PhoneTextMediaIndexParam"}],"responses":{"200":{"description":"The photo bytes"},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/platform/feedback":{"get":{"operationId":"getPlatformFeedback","summary":"How customers rated booking online, every studio","description":"Platform admins only — the emails in `PLATFORM_ADMIN_EMAILS`. The thumbs given on receipts: totals and the happy rate over the period, by location and by where they booked (`page`, `embed`), and the newest responses with their comments. `days` is 7, 30 (the default), 90 or `all`; `rating` narrows the list to one thumb.","tags":["system"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"query","name":"days","schema":{"type":"string","enum":["7","30","90","all"]}},{"in":"query","name":"rating","schema":{"type":"string","enum":["up","down"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"generatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"period":{"type":"object","properties":{"days":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"since":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["days","since"],"additionalProperties":false},"rating":{"anyOf":[{"$ref":"#/components/schemas/FeedbackRating"},{"type":"null"}]},"totals":{"type":"object","properties":{"responses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"up":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"down":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"happyRate":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"Thumbs up as a percentage of responses; null with none."}},"required":["responses","up","down","happyRate"],"additionalProperties":false},"byLocation":{"type":"array","items":{"type":"object","properties":{"businessId":{"$ref":"#/components/schemas/Uuid"},"businessName":{"type":"string"},"locationId":{"$ref":"#/components/schemas/Uuid"},"locationName":{"type":"string"},"responses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"up":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"down":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"happyRate":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"Thumbs up as a percentage of responses; null with none."},"lastAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["businessId","businessName","locationId","locationName","responses","up","down","happyRate","lastAt"],"additionalProperties":false}},"bySource":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string"},"responses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"up":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"down":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"happyRate":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"Thumbs up as a percentage of responses; null with none."}},"required":["source","responses","up","down","happyRate"],"additionalProperties":false}},"responses":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"rating":{"$ref":"#/components/schemas/FeedbackRating"},"comment":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"businessId":{"$ref":"#/components/schemas/Uuid"},"businessName":{"type":"string"},"locationId":{"$ref":"#/components/schemas/Uuid"},"locationName":{"type":"string"},"bookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookingReference":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringName":{"anyOf":[{"type":"string"},{"type":"null"}]},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["id","rating","comment","source","createdAt","businessId","businessName","locationId","locationName","bookingId","bookingReference","offeringName","cartId"],"additionalProperties":false}}},"required":["generatedAt","period","rating","totals","byLocation","bySource","responses"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/places/autocomplete":{"post":{"operationId":"placesAutocomplete","summary":"Autocomplete an address","description":"Server-side proxy for the Google Places autocomplete API: the key never ships to the browser. Returns trimmed suggestions (`placeId`, primary/secondary text). An empty `query` — or a missing Places key in the environment — returns an empty list so the form can fall back to free text.","tags":["system"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceAutocompleteBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PlaceAutocompleteResponse"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/places/details":{"post":{"operationId":"placesDetails","summary":"Resolve a place to an address and coordinates","description":"Server-side proxy for the Google Places details API, completing an autocomplete selection. Returns the formatted address, coordinates, and jurisdiction components, or all-null fields when the Places key is unset — the caller treats that as \"keep the free-text address\".","tags":["system"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceDetailsBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PlaceDetailsResponse"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/places/resolve":{"post":{"operationId":"placesResolve","summary":"Qualify a free-text address","description":"Text Search for an address that was typed, pasted, or scraped rather than picked from autocomplete. Returns the same shape as details, or all-null fields when Places cannot resolve the string.","tags":["system"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceResolveBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PlaceDetailsResponse"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/products":{"get":{"operationId":"listProducts","summary":"List products","description":"Every product but the archived, in display order, with its options, their SKUs, and on hand and available per location. `status=archived` lists the archived ones. `soldVia` filters by where it sells. Cursor-paged: `{ items, nextCursor }`. Requires feature `location.view`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"description":"Only what sells there: its own products and those sold at every location. Omitted: every product.","$ref":"#/components/schemas/Uuid"},"description":"Only what sells there: its own products and those sold at every location. Omitted: every product."},{"in":"query","name":"status","schema":{"description":"One status. Omitted: draft, published and hidden.","type":"string","enum":["draft","published","hidden","archived"]},"description":"One status. Omitted: draft, published and hidden."},{"in":"query","name":"soldVia","schema":{"description":"`shop` · `add_on` · `both` · `none`, derived from `shopListed` and the listings offering it.","type":"string","enum":["shop","add_on","both","none"]},"description":"`shop` · `add_on` · `both` · `none`, derived from `shopListed` and the listings offering it."},{"in":"query","name":"limit","schema":{"description":"Default 50, at most 200.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"description":"Default 50, at most 200."},{"in":"query","name":"cursor","schema":{"description":"The previous page's `nextCursor`. Omit it for the first page.","type":"string"},"description":"The previous page's `nextCursor`. Omit it for the first page."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProductPage"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createProduct","summary":"Create a product","description":"Creates a draft with at least one option. `shopListed` defaults to true. A SKU already on another live option is a field error on `variants`. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/products/order":{"patch":{"operationId":"reorderProducts","summary":"Reorder products","description":"The Products list's drag order, which the shop follows. `ids` must name every live product exactly once — or, with `locationId`, every product that sells there. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderProductsBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}":{"get":{"operationId":"getProduct","summary":"Get a product","description":"One product with its live options and their stock. Archived products stay readable. Requires feature `location.view`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateProduct","summary":"Update a product","description":"`variants` is replace-all, keeping the ids it names. A product that is for sale refuses an edit that would leave an option without a price. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/publish":{"post":{"operationId":"publishProduct","summary":"Put a product on sale","description":"Draft or Hidden → For sale (`published`). Needs a price on every option, in the business currency; otherwise a field error on `variants`. Switches the Products section on. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/hide":{"post":{"operationId":"hideProduct","summary":"Hide a product","description":"Draft or For sale → Hidden: still in the console, off the shop. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/archive":{"post":{"operationId":"archiveProduct","summary":"Archive a product","description":"Archived for good. Its options are archived with it, which frees their SKUs; every ledger row that names them still reads them. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/duplicate":{"post":{"operationId":"duplicateProduct","summary":"Copy a product as a new draft","description":"The same options, prices and photos; no SKUs (they are unique) and no stock (the ledger is the source's). Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/variants/{variantId}/stock":{"get":{"operationId":"listStockMovements","summary":"List an option's stock ledger","description":"Every change to one option's stock, newest first: received, counted, adjusted, sold and returned, each with who and why. Archived options keep their history. Cursor-paged: `{ items, nextCursor }`. Requires feature `location.view`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"},{"$ref":"#/components/parameters/VariantIdParam"},{"in":"query","name":"locationId","schema":{"description":"One location's rows. Omitted: every location.","$ref":"#/components/schemas/Uuid"},"description":"One location's rows. Omitted: every location."},{"in":"query","name":"limit","schema":{"description":"Default 50, at most 200.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"description":"Default 50, at most 200."},{"in":"query","name":"cursor","schema":{"description":"The previous page's `nextCursor`. Omit it for the first page.","type":"string"},"description":"The previous page's `nextCursor`. Omit it for the first page."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StockMovementPage"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"recordStockMovement","summary":"Record received, counted or adjusted stock","description":"Writes one ledger row under the option's lock. `received` adds `quantity`; `counted` sets on hand to `quantity` and writes the difference (a count of 5 on 8 writes −3); `adjusted` writes `quantity` as a signed change. Refused on a product that does not track stock. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"},{"$ref":"#/components/parameters/VariantIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordStockBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StockResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/images":{"get":{"operationId":"listProductImages","summary":"List a product's photos","description":"In order; the first is the cover. Requires feature `location.view`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"uploadProductImage","summary":"Upload a product photo","description":"Adds the file to the photo library and places it last on the product. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadImageBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/images/attach":{"post":{"operationId":"attachProductImage","summary":"Attach a library photo to a product","description":"Places a photo already in the library. 201 when placed, 200 when it was already there. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachAssetBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/products/{productId}/images/order":{"patch":{"operationId":"reorderProductImages","summary":"Reorder a product's photos","description":"`ids` names every photo on the product once; the first becomes the cover. Requires feature `catalog.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ProductIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderImagesBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/order-lines/{orderLineId}/cancel":{"post":{"operationId":"cancelOrderLine","summary":"Cancel an order line — refund and restock","description":"Gated on `expectedEffect` — declare it first with `POST /businesses/{businessId}/money-effects`, action `order_line.cancel`. A paid line is canceled and its units go back on the shelf, then its paid money is refunded on the instrument that paid it; a picked-up line coming back is the same call. A line still in a cart leaves the cart and nothing moves. Requires feature `booking.manage`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OrderLineIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderLineActionBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderLine"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/order-lines":{"get":{"operationId":"listOrderLines","summary":"List pickups","description":"Bookings → Pickups: every paid product line bought on its own at a location, newest first — `state=waiting` (default) not yet handed over, `state=picked_up` already collected. Lines sold with a class are on that class's roster instead. At most 200. Requires feature `booking.view`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},{"in":"query","name":"state","schema":{"type":"string","enum":["waiting","picked_up"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PickupLine"}}},"required":["items"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/order-lines/{orderLineId}/fulfill":{"post":{"operationId":"fulfillOrderLine","summary":"Mark an order line picked up","description":"Gated on `expectedEffect` — action `order_line.fulfill`, which declares no movements. Only a paid line can be handed over; marking it again changes nothing. Stamps when and by whom. Requires feature `booking.checkin`.","tags":["products"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/OrderLineIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderLineActionBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderLine"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/money":{"get":{"operationId":"getMoneyReport","summary":"Payments report for a period","description":"The period's statement — sales down to the bank — from the closed set, in the provider's own words: a Stripe studio's payouts and processing fees, or a TRX studio's deposits, its statements' fees for months wholly in the period and the card networks' interchange TRX states per sale for months with no statement yet. A cost not stated yet is a `gaps` entry, and then there is no net and `takeHome` is null. `overview` adds the latest deposits, open disputes with the nearest deadline, and the last closed month's fees and effective rate. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"timezone":{"type":"string"},"basis":{"type":"string","const":"cash"}},"required":["from","to","timezone","basis"],"additionalProperties":false},"provider":{"type":"string","enum":["stripe","trx"]},"overview":{"type":"object","properties":{"deposits":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The processor's id: a Stripe payout (`po_…`) or a TRX batch GUID."},"provider":{"type":"string","enum":["stripe","trx"]},"date":{"anyOf":[{"type":"string"},{"type":"null"}]},"settledOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX: the day the batch settled (else closed) in the studio zone — what a settled batch without a deposit date is dated by. Null for Stripe."},"sentAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the processor sent the money: Stripe — the payout's `created`; TRX — when the batch settled (else closed). Null while a TRX batch is open."},"status":{"type":"string","enum":["paid","in_transit","pending","failed","canceled","batching","settled","deposit_expected","deposited","watching"],"description":"Stripe's payout status, or TRX's batch status. The console reads them in three words for both processors (`src/helpers/money-state.ts`): **Pending** — `batching` (TRX's open batch); **On the way** — `pending`, `in_transit` (a Stripe payout sent, not arrived), `settled` (TRX settled the batch and has not stated a deposit date), `deposit_expected` (a TRX date ahead); **Deposited** — `paid`, `deposited` (a TRX deposit date on or before today). `failed`, `canceled` and `watching` keep their own words."},"watchingReason":{"anyOf":[{"type":"string","enum":["unsettled","unreconciled"]},{"type":"null"}]},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"currency":{"type":"string"},"paymentsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refundsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bankRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankName":{"anyOf":[{"type":"string"},{"type":"null"}]},"batchName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX: the batch as TRX's portal names it (`Batch # GATEWAY2627700837300`), once the nightly sync has read it — show `id` (the batch GUID) until then. Always null for Stripe."},"otherAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"shared":{"type":"boolean"},"automatic":{"type":"boolean"}},"required":["id","provider","date","settledOn","sentAt","status","watchingReason","amount","currency","paymentsCount","refundsCount","bankRef","bankLast4","bankName","batchName","otherAmount","shared","automatic"],"additionalProperties":false}},"disputes":{"type":"object","properties":{"openCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amounts":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["currency","amount"],"additionalProperties":false}},"nearestDueBy":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["openCount","amounts","nearestDueBy"],"additionalProperties":false},"lastClosedMonth":{"anyOf":[{"type":"object","properties":{"month":{"type":"string"},"currency":{"type":"string"},"fees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sales":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveRate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"fees ÷ sales as a fraction — derived from two stated facts."},"derived":{"type":"boolean","const":true},"basis":{"type":"string","enum":["trx_statement","stripe_balance_transactions"]},"statementDate":{"type":"string"},"sharedAccount":{"type":"boolean"}},"required":["month","currency","fees","sales","effectiveRate","derived","basis"],"additionalProperties":false},{"type":"null"}]},"lastClosedMonthReason":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["deposits","disputes","lastClosedMonth","lastClosedMonthReason"],"additionalProperties":false},"blocks":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string"},"provider":{"type":"string","enum":["stripe","trx"]},"lines":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"deduction":{"type":"boolean"},"subtotal":{"type":"boolean"},"group":{"type":"string","enum":["sales","bank"]},"hint":{"type":"string"},"linkTarget":{"type":"object","properties":{"panel":{"type":"string","enum":["payouts","transactions"]},"payoutId":{"type":"string"}},"required":["panel"],"additionalProperties":false}},"required":["key","label","amount"],"additionalProperties":false}},"takeHome":{"anyOf":[{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"youKeep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"charged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"slices":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["you_keep","sales_tax","stripe_fees","booking_fees"]},"label":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"share":{"type":"number"}},"required":["key","label","amount","share"],"additionalProperties":false}}},"required":["total","youKeep","charged","slices"],"additionalProperties":false},{"type":"null"}],"description":"Null while any cost of the period is not stated yet (a TRX statement to come); `gaps` says which."},"gaps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["trx_fees_on_statement","trx_fees_partial_month","trx_fees_shared_account","card_networks_missing_detail","location_view"]},"label":{"type":"string"},"month":{"type":"string"},"statementDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["key","label"],"additionalProperties":false,"description":"A figure not stated yet, said in words instead of guessed (architecture/20 rule 7)."}},"payouts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"paidAt":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"transactionCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"linkTarget":{"type":"object","properties":{"panel":{"type":"string","enum":["payouts","transactions"]},"payoutId":{"type":"string"}},"required":["panel"],"additionalProperties":false},"transactionsPayoutId":{"type":"string"},"bankLast4":{"description":"The bank account's last four, where the processor stated it.","type":"string"},"traceId":{"description":"The deposit's reference on the bank statement: Stripe's trace id, TRX's deposit ReferenceNumber.","type":"string"}},"required":["id","paidAt","amount","transactionCount"],"additionalProperties":false}},"payoutDetailAvailable":{"type":"boolean"},"payoutDetailNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"stripeProcessingFees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unmatchedStripe":{"anyOf":[{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"net":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["count","net","fees"],"additionalProperties":false},{"type":"null"}]},"charged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"What customers were charged in the period: net of discounts, before refunds (tax and any customer-paid fee included). The Payments Overview's Sales."},"refunded":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"What went back to customers in the period (refunds and voids), positive. Sales − refunded = total collected."},"waiting":{"anyOf":[{"type":"object","properties":{"pending":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"onTheWay":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["pending","onTheWay"],"additionalProperties":false},{"type":"null"}],"description":"The money not in the bank yet, split by the Payments tab's words: `pending` — TRX's open batch, Stripe's balance; `onTheWay` — a TRX batch settled with no deposit date or dated ahead, a Stripe payout pending or in transit. Sums to the `on_the_way` (TRX) / `awaiting_payout` (Stripe) line. Null when nothing is waiting or the line is not drawn."}},"required":["currency","provider","lines","takeHome","gaps","payouts","payoutDetailAvailable","payoutDetailNote","stripeProcessingFees","unmatchedStripe","charged","refunded","waiting"],"additionalProperties":false}},"stripeConnected":{"type":"boolean"},"settlementAsOf":{"anyOf":[{"type":"string"},{"type":"null"}]},"quickbooksPosting":{"anyOf":[{"type":"object","properties":{"postedThrough":{"anyOf":[{"type":"string"},{"type":"null"}]},"failedCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["postedThrough","failedCount"],"additionalProperties":false},{"type":"null"}]},"locationNote":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["period","provider","overview","blocks","stripeConnected","settlementAsOf","quickbooksPosting","locationNote"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"period":{"from":"2026-10-01","to":"2026-10-31","timezone":"America/Los_Angeles","basis":"cash"},"provider":"trx","overview":{"deposits":[{"id":"BATCH00000000A7","provider":"trx","date":"2026-09-26","settledOn":"2026-09-25","sentAt":"2026-09-26T04:45:00.000Z","status":"deposited","watchingReason":null,"amount":8000,"currency":"USD","paymentsCount":2,"refundsCount":0,"bankRef":"900012345","bankLast4":"6789","bankName":null,"batchName":"GATEWAY2626800041200","otherAmount":null,"shared":false,"automatic":true}],"disputes":{"openCount":1,"amounts":[{"currency":"USD","amount":3000}],"nearestDueBy":null},"lastClosedMonth":{"month":"2026-09","currency":"USD","fees":4850,"sales":166000,"effectiveRate":0.029217,"derived":true,"basis":"trx_statement","statementDate":"2026-09-30"},"lastClosedMonthReason":null},"blocks":[{"currency":"USD","provider":"trx","lines":[{"key":"gross_sales","label":"Gross sales","amount":16000,"group":"sales"},{"key":"total_collected","label":"Total collected","amount":13000,"subtotal":true,"group":"sales"},{"key":"through_trx","label":"Collected through TRX","amount":13000,"subtotal":true,"group":"bank","linkTarget":{"panel":"transactions"}},{"key":"card_networks","label":"Card networks so far","amount":254,"deduction":true,"group":"bank","linkTarget":{"panel":"transactions"}},{"key":"deposited","label":"Deposited to your bank","amount":8000,"subtotal":true,"group":"bank","linkTarget":{"panel":"payouts"}},{"key":"on_the_way","label":"Not yet deposited","amount":5000,"group":"bank","linkTarget":{"panel":"payouts"}}],"takeHome":null,"gaps":[{"key":"trx_fees_on_statement","label":"TRX fees: on your October 2026 statement.","month":"2026-10","statementDate":null}],"payouts":[{"id":"BATCH00000000A7","paidAt":"2026-10-02T00:00:00.000Z","amount":8000,"transactionCount":2,"bankLast4":"6789","traceId":"900012345","linkTarget":{"panel":"payouts","payoutId":"BATCH00000000A7"}}],"payoutDetailAvailable":true,"payoutDetailNote":null,"stripeProcessingFees":0,"unmatchedStripe":null,"charged":15000,"refunded":2000,"waiting":{"pending":3000,"onTheWay":2000}}],"stripeConnected":false,"settlementAsOf":null,"quickbooksPosting":null,"locationNote":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/tax":{"get":{"operationId":"getTaxReport","summary":"Tax report for a period","description":"Cash-basis tax collected and refunded in a period, grouped by configured tax rate. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"timezone":{"type":"string"},"basis":{"type":"string","const":"cash"}},"required":["from","to","timezone","basis"],"additionalProperties":false},"rows":{"type":"array","items":{"type":"object","properties":{"taxRateId":{"type":"string"},"name":{"type":"string"},"ratePercent":{"type":"number"},"jurisdiction":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"location":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxableSales":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"taxCollected":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"taxRefunded":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"netTax":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["taxRateId","name","ratePercent","jurisdiction","registrationNumber","location","taxableSales","taxCollected","taxRefunded","netTax"],"additionalProperties":false}},"totalNetTax":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["period","rows","totalNetTax","currency"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/transactions":{"get":{"operationId":"getTransactionsReport","summary":"Transaction lines for a period","description":"Paginated cash-basis ledger lines for a period. Optional `paymentIds` restricts to those payments (payout drill-down). Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}},{"in":"query","name":"cursor","schema":{"type":"string"}},{"in":"query","name":"paymentIds","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"timezone":{"type":"string"},"basis":{"type":"string","const":"cash"}},"required":["from","to","timezone","basis"],"additionalProperties":false},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"occurredAt":{"type":"string"},"localDate":{"type":"string"},"kind":{"type":"string"},"source":{"type":"string"},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardBrand":{"anyOf":[{"type":"string"},{"type":"null"}]},"depositRef":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The deposit this movement landed in: a Stripe payout id or a TRX batch GUID."},"depositDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"depositSettled":{"type":"boolean","description":"TRX: the batch is settled. With no depositDate it is settled and not yet deposited."},"bookingReference":{"anyOf":[{"type":"string"},{"type":"null"}]},"listingName":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringType":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Listing type on a booking row. Prefer `soldKind`. Kept so existing clients keep working.","deprecated":true},"soldKind":{"anyOf":[{"type":"string","enum":["class","session","space","membership","product"]},{"type":"null"}],"description":"What this allocation sold — the Transactions sold-kind column."},"quantity":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Set on product rows only. Bookings keep spots as a separate noun."},"sessionDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"gross":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"tax":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingFee":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"bookingId":{"anyOf":[{"type":"string"},{"type":"null"}]},"orderLineId":{"anyOf":[{"type":"string"},{"type":"null"}]},"stripePaymentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"trxReference":{"anyOf":[{"type":"string"},{"type":"null"}]},"memo":{"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"type":"string"},"refundReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"voided":{"type":"boolean","description":"A refund row that was a TRX void (the sale cancelled before its batch closed)."}},"required":["id","occurredAt","localDate","kind","source","customerName","customerId","cardLast4","cardBrand","depositRef","depositDate","depositSettled","bookingReference","listingName","offeringType","soldKind","quantity","sessionDate","gross","tax","bookingFee","currency","locationName","paymentId","bookingId","orderLineId","stripePaymentId","trxReference","memo","category","refundReason","voided"],"additionalProperties":false}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]},"stripeConnected":{"type":"boolean"},"unmatchedStripe":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"occurredAt":{"type":"string"},"localDate":{"type":"string"},"type":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fee":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"net":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"stripePaymentId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","occurredAt","localDate","type","amount","fee","net","currency","stripePaymentId"],"additionalProperties":false}},"settlementAsOf":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["period","rows","nextCursor","stripeConnected","unmatchedStripe","settlementAsOf"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/transactions/export":{"get":{"operationId":"exportTransactionsCsv","summary":"Export transaction lines as CSV","description":"Same transaction lines as the report, as a CSV download. Columns include `category` (`categorizeLedgerRow`) and `refund_reason` (`refundReasonLabel`; empty on non-refunds). Filename is `transactions-{from}-{to}.csv`. Requires feature `finance.export`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"CSV file contents","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/journal/export":{"get":{"operationId":"exportJournalCsv","summary":"Export journal lines as CSV","description":"One row per journal line for the period (`batch_key, kind, local_date, channel, category, tax_rate, account_hint, debit, credit, currency, memo, count`). Filename is `journal-{from}-{to}.csv`. The journal is business-wide. Requires feature `finance.export`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"CSV file contents","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/tax/export":{"get":{"operationId":"exportTaxCsv","summary":"Export the tax report as CSV","description":"Tax report rows plus `location`. Filename is `tax-{from}-{to}.csv`. Requires feature `finance.export`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"CSV file contents","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/transactions/{paymentId}":{"get":{"operationId":"getTransactionDetail","summary":"One payment: what it bought, what it cost, its timeline, card, refunds and disputes","description":"Stripe: the processing fee (every `fee_details` entry on the charge's balance transaction but the application fee), the platform fee net of reversals, the balance transaction's `net`, and fee ÷ amount as `effectivePercent` (`derived: true` — Stripe states no per-charge rate); the card's checks, wallet, 3DS and risk. TRX: the card network's interchange TRX states for the sale and `processorFees: on_statement` — never a TRX fee number or a net. Timeline steps appear only once stored. A manual payment answers `provider: manual` with no card or cost. Another business's payment is 404. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/ReportPaymentIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"paymentId":{"type":"string"},"provider":{"type":"string","enum":["stripe","trx","manual"]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"status":{"type":"string"},"customer":{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},"items":{"type":"array","items":{"type":"object","properties":{"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"soldKind":{"anyOf":[{"type":"string","enum":["class","session","space","membership","product"]},{"type":"null"}]},"bookingId":{"anyOf":[{"type":"string"},{"type":"null"}]},"bookingReference":{"anyOf":[{"type":"string"},{"type":"null"}]},"orderLineId":{"anyOf":[{"type":"string"},{"type":"null"}]},"sessionDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["label","soldKind","bookingId","bookingReference","orderLineId","sessionDate","quantity","locationName"],"additionalProperties":false}},"processorRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"cost":{"anyOf":[{"anyOf":[{"type":"object","properties":{"provider":{"type":"string","const":"stripe"},"processingFee":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"platformFee":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"net":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectivePercent":{"anyOf":[{"type":"number"},{"type":"null"}]},"derived":{"type":"boolean","const":true},"balanceTransactionId":{"type":"string"}},"required":["provider","processingFee","platformFee","net","effectivePercent","derived","balanceTransactionId"],"additionalProperties":false},{"type":"object","properties":{"provider":{"type":"string","const":"trx"},"cardNetwork":{"anyOf":[{"type":"object","properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"perItemMinor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"percent":{"anyOf":[{"type":"string"},{"type":"null"}]},"amountMinor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"amountExact":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["description","perItemMinor","percent","amountMinor","amountExact"],"additionalProperties":false},{"type":"null"}]},"cardNetworkMissingReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"processorFees":{"type":"object","properties":{"state":{"type":"string","const":"on_statement"},"statementMonth":{"anyOf":[{"type":"string"},{"type":"null"}]},"statementDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["state","statementMonth","statementDate"],"additionalProperties":false}},"required":["provider","cardNetwork","cardNetworkMissingReason","processorFees"],"additionalProperties":false}]},{"type":"null"}]},"costMissingReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"timeline":{"type":"array","items":{"type":"object","properties":{"step":{"type":"string","enum":["paid","settled","deposited","voided"]},"at":{"type":"string"},"depositId":{"type":"string"},"batchName":{"description":"settled / deposited, TRX: the batch as TRX's portal names it; null until read — show the GUID.","anyOf":[{"type":"string"},{"type":"null"}]},"batchGuid":{"description":"settled, TRX: the batch GUID.","type":"string"},"status":{"type":"string"},"bankRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"sentAt":{"description":"deposited, Stripe: when Stripe created the payout.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["step","at"],"additionalProperties":false}},"card":{"anyOf":[{"anyOf":[{"type":"object","properties":{"provider":{"type":"string","const":"stripe"},"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]},"funding":{"anyOf":[{"type":"string"},{"type":"null"}]},"network":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"wallet":{"anyOf":[{"type":"string"},{"type":"null"}]},"cvcCheck":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCodeCheck":{"anyOf":[{"type":"string"},{"type":"null"}]},"line1Check":{"anyOf":[{"type":"string"},{"type":"null"}]},"threeDSecure":{"anyOf":[{"type":"string"},{"type":"null"}]},"riskLevel":{"anyOf":[{"type":"string"},{"type":"null"}]},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}]},"sellerMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"receiptUrl":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["provider","brand","last4","funding","network","country","wallet","cvcCheck","postalCodeCheck","line1Check","threeDSecure","riskLevel","outcome","sellerMessage","receiptUrl"],"additionalProperties":false},{"type":"object","properties":{"provider":{"type":"string","const":"trx"},"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]},"funding":{"anyOf":[{"type":"string"},{"type":"null"}]},"prepaid":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"issuer":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardholderName":{"anyOf":[{"type":"string"},{"type":"null"}]},"avsResult":{"anyOf":[{"type":"string"},{"type":"null"}]},"cvvResult":{"anyOf":[{"type":"string"},{"type":"null"}]},"approvalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["provider","brand","last4","funding","prepaid","issuer","cardholderName","avsResult","cvvResult","approvalCode","productCode"],"additionalProperties":false}]},{"type":"null"}]},"processor":{"anyOf":[{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"]},"entry":{"anyOf":[{"type":"string","enum":["typed","saved_card","wallet"]},{"type":"null"}],"description":"How the card came in: typed into a checkout, a card on file, or a wallet."},"wallet":{"anyOf":[{"type":"string"},{"type":"null"}]},"reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stripe ch_… / TRX's sale GUID."},"paymentIntentId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stripe only: the PaymentIntent."},"networkStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stripe only: the charge outcome's network_status."},"sellerMessage":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stripe only: the outcome's seller_message."},"purchaseId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX only: the IndustryData.PurchaseId the Sale sent."},"responseText":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX only: TRX's ResponseText for the sale."},"batchName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX only: the batch as TRX's portal names it; null until read."},"batchGuid":{"anyOf":[{"type":"string"},{"type":"null"}]},"settledAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX only: when TRX settled the batch."},"acquirerReference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX only: DailyDetail's acquirer reference number, when read."}},"required":["provider","entry","wallet","reference","paymentIntentId","networkStatus","sellerMessage","purchaseId","responseText","batchName","batchGuid","settledAt","acquirerReference"],"additionalProperties":false},{"type":"null"}],"description":"The processor's own facts beyond the card (QA F23); null on a manual payment. Absent facts are null, never guessed."},"refunds":{"type":"array","items":{"type":"object","properties":{"ledgerId":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"occurredAt":{"type":"string"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]},"processorRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"processorKind":{"anyOf":[{"type":"string","enum":["refund","return","void"]},{"type":"null"}]},"depositRef":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["ledgerId","amount","occurredAt","reason","processorRef","processorKind","depositRef"],"additionalProperties":false}},"disputes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string","enum":["stripe","trx"]},"reference":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"reason":{"type":"string"},"state":{"type":"string","enum":["open","won","lost","closed"]},"status":{"type":"string"},"evidenceDueBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"openedAt":{"type":"string"},"closedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"fee":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["id","provider","reference","amount","currency","reason","state","status","evidenceDueBy","openedAt","closedAt","fee"],"additionalProperties":false}}},"required":["paymentId","provider","amount","currency","status","customer","items","processorRef","cost","costMissingReason","timeline","card","processor","refunds","disputes"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"paymentId":"7d0f1c1e-4a55-4d4c-9f1e-2b0c3e5a8f10","provider":"stripe","amount":6500,"currency":"USD","status":"captured","customer":{"id":"c2b6a0e4-1f3d-4b7a-9a51-0e8c7d6f5a42","name":"Ada Lovelace"},"items":[{"label":"Wheel Throwing","soldKind":"class","bookingId":"0b7a5c3e-2d1f-4e8a-b6c4-9f0e1d2c3b4a","bookingReference":"K7Q2MX","orderLineId":null,"sessionDate":"2026-10-10T17:00:00.000Z","quantity":null,"locationName":"Main"}],"processorRef":"ch_3S9fX1AulkIu3Ep0q1Kp8a2b","cost":{"provider":"stripe","processingFee":219,"platformFee":130,"net":6151,"effectivePercent":3.37,"derived":true,"balanceTransactionId":"txn_3S9fX1AulkIu3Ep0q1Kp8a2b"},"costMissingReason":null,"timeline":[{"step":"paid","at":"2026-10-04T16:02:11.000Z"},{"step":"settled","at":"2026-10-06T00:00:00.000Z"},{"step":"deposited","at":"2026-10-08T00:00:00.000Z","depositId":"po_1S9gB6AulkIu3Ep0payout01","status":"paid","bankRef":"20261008MMQFMPU8000123456","bankLast4":"6789"}],"card":{"provider":"stripe","brand":"visa","last4":"4242","funding":"credit","network":"visa","country":"US","wallet":null,"cvcCheck":"pass","postalCodeCheck":"pass","line1Check":"pass","threeDSecure":null,"riskLevel":"normal","outcome":"authorized","sellerMessage":"Payment complete.","receiptUrl":"https://pay.stripe.com/receipts/payment/example"},"processor":{"provider":"stripe","entry":"typed","wallet":null,"reference":"ch_3S9fX1AulkIu3Ep0q1Kp8a2b","paymentIntentId":"pi_3S9fX1AulkIu3Ep0q1Kp8a2b","networkStatus":"approved_by_network","sellerMessage":"Payment complete.","purchaseId":null,"responseText":null,"batchName":null,"batchGuid":null,"settledAt":null,"acquirerReference":null},"refunds":[],"disputes":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/deposits":{"get":{"operationId":"getDeposits","summary":"Deposits dated in a period — Stripe payouts or TRX batches, one shape","description":"Newest first. `id` is the processor's own (so `?payout=` / `?batch=` deep links resolve), `amount` is what reaches the bank (a TRX shared account's row is our part, with `otherAmount` beside it), `bankRef` the reference on the bank statement. TRX lists a batch with no deposit date yet when the period reaches today, and `notYetDeposited` is the approved sales not yet in a settled batch; Stripe's equivalent is its balance. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"]},"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"timezone":{"type":"string"},"basis":{"type":"string","const":"cash"}},"required":["from","to","timezone","basis"],"additionalProperties":false},"deposits":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The processor's id: a Stripe payout (`po_…`) or a TRX batch GUID."},"provider":{"type":"string","enum":["stripe","trx"]},"date":{"anyOf":[{"type":"string"},{"type":"null"}]},"settledOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX: the day the batch settled (else closed) in the studio zone — what a settled batch without a deposit date is dated by. Null for Stripe."},"sentAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the processor sent the money: Stripe — the payout's `created`; TRX — when the batch settled (else closed). Null while a TRX batch is open."},"status":{"type":"string","enum":["paid","in_transit","pending","failed","canceled","batching","settled","deposit_expected","deposited","watching"],"description":"Stripe's payout status, or TRX's batch status. The console reads them in three words for both processors (`src/helpers/money-state.ts`): **Pending** — `batching` (TRX's open batch); **On the way** — `pending`, `in_transit` (a Stripe payout sent, not arrived), `settled` (TRX settled the batch and has not stated a deposit date), `deposit_expected` (a TRX date ahead); **Deposited** — `paid`, `deposited` (a TRX deposit date on or before today). `failed`, `canceled` and `watching` keep their own words."},"watchingReason":{"anyOf":[{"type":"string","enum":["unsettled","unreconciled"]},{"type":"null"}]},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"currency":{"type":"string"},"paymentsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refundsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bankRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankName":{"anyOf":[{"type":"string"},{"type":"null"}]},"batchName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX: the batch as TRX's portal names it (`Batch # GATEWAY2627700837300`), once the nightly sync has read it — show `id` (the batch GUID) until then. Always null for Stripe."},"otherAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"shared":{"type":"boolean"},"automatic":{"type":"boolean"}},"required":["id","provider","date","settledOn","sentAt","status","watchingReason","amount","currency","paymentsCount","refundsCount","bankRef","bankLast4","bankName","batchName","otherAmount","shared","automatic"],"additionalProperties":false}},"notYetDeposited":{"anyOf":[{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["count","amount","currency"],"additionalProperties":false},{"type":"null"}]},"waiting":{"anyOf":[{"type":"object","properties":{"pending":{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["count","amount"],"additionalProperties":false},"onTheWay":{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["count","amount"],"additionalProperties":false}},"required":["pending","onTheWay"],"additionalProperties":false},{"type":"null"}],"description":"TRX: `notYetDeposited` split — Pending (in TRX's open batch) and On the way (in a batch TRX settled with no deposit date stated). Null on Stripe."},"notYetDepositedNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationNote":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["provider","period","deposits","notYetDeposited","waiting","notYetDepositedNote","locationNote"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"provider":"trx","period":{"from":"2026-09-01","to":"2026-09-30","timezone":"America/Los_Angeles","basis":"cash"},"deposits":[{"id":"BATCH00000000A7","provider":"trx","date":"2026-09-26","settledOn":"2026-09-25","sentAt":"2026-09-26T04:45:00.000Z","status":"deposited","watchingReason":null,"amount":8000,"currency":"USD","paymentsCount":2,"refundsCount":0,"bankRef":"900012345","bankLast4":"6789","bankName":null,"batchName":"GATEWAY2626800041200","otherAmount":null,"shared":false,"automatic":true}],"notYetDeposited":{"count":1,"amount":5000,"currency":"USD"},"waiting":{"pending":{"count":1,"amount":5000},"onTheWay":{"count":0,"amount":0}},"notYetDepositedNote":null,"locationNote":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/deposits/{depositId}":{"get":{"operationId":"getDeposit","summary":"One deposit with its breakdown and movements","description":"Stripe: Σ charges + Σ refunds − Σ Stripe fees − Σ platform fees + disputes + other over the balance transactions Stripe linked to the payout, compared to the payout (`reconciled`, `delta` — never forced); a manual payout Stripe did not itemize answers `breakdown: null` with the reason. TRX: Σ sales − Σ returns + adjustments (ours), the other system's line on a shared account, TRX's net, and `fees: on_statement`. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/DepositIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","description":"The processor's id: a Stripe payout (`po_…`) or a TRX batch GUID."},"provider":{"type":"string","enum":["stripe","trx"]},"date":{"anyOf":[{"type":"string"},{"type":"null"}]},"settledOn":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX: the day the batch settled (else closed) in the studio zone — what a settled batch without a deposit date is dated by. Null for Stripe."},"sentAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the processor sent the money: Stripe — the payout's `created`; TRX — when the batch settled (else closed). Null while a TRX batch is open."},"status":{"type":"string","enum":["paid","in_transit","pending","failed","canceled","batching","settled","deposit_expected","deposited","watching"],"description":"Stripe's payout status, or TRX's batch status. The console reads them in three words for both processors (`src/helpers/money-state.ts`): **Pending** — `batching` (TRX's open batch); **On the way** — `pending`, `in_transit` (a Stripe payout sent, not arrived), `settled` (TRX settled the batch and has not stated a deposit date), `deposit_expected` (a TRX date ahead); **Deposited** — `paid`, `deposited` (a TRX deposit date on or before today). `failed`, `canceled` and `watching` keep their own words."},"watchingReason":{"anyOf":[{"type":"string","enum":["unsettled","unreconciled"]},{"type":"null"}]},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"currency":{"type":"string"},"paymentsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refundsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bankRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankName":{"anyOf":[{"type":"string"},{"type":"null"}]},"batchName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX: the batch as TRX's portal names it (`Batch # GATEWAY2627700837300`), once the nightly sync has read it — show `id` (the batch GUID) until then. Always null for Stripe."},"otherAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"shared":{"type":"boolean"},"automatic":{"type":"boolean"},"breakdown":{"anyOf":[{"anyOf":[{"type":"object","properties":{"provider":{"type":"string","const":"stripe"},"charges":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"refunds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"stripeFees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"platformFees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"disputes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"other":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"depositAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"reconciled":{"type":"boolean"},"delta":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["provider","charges","refunds","stripeFees","platformFees","disputes","other","total","depositAmount","reconciled","delta"],"additionalProperties":false},{"type":"object","properties":{"provider":{"type":"string","const":"trx"},"sales":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"returns":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"adjustments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"ours":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"other":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"depositAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"reconciled":{"type":"boolean"},"delta":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"fees":{"type":"object","properties":{"state":{"type":"string","const":"on_statement"},"statementMonth":{"anyOf":[{"type":"string"},{"type":"null"}]},"statementDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["state","statementMonth","statementDate"],"additionalProperties":false}},"required":["provider","sales","returns","adjustments","ours","other","depositAmount","reconciled","delta","fees"],"additionalProperties":false}]},{"type":"null"}]},"notItemizedReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"movements":{"type":"array","items":{"type":"object","properties":{"paymentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"kind":{"type":"string","enum":["payment","refund","adjustment","dispute","other"]},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"item":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"cardBrand":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"occurredAt":{"type":"string"},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["paymentId","kind","customerName","item","amount","currency","cardBrand","cardLast4","occurredAt","reference"],"additionalProperties":false}},"failure":{"anyOf":[{"type":"object","properties":{"code":{"anyOf":[{"type":"string"},{"type":"null"}]},"message":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["code","message"],"additionalProperties":false},{"type":"null"}]},"voided":{"description":"TRX: our sales voided while the batch was open — TRX's batch detail counts them as Voided; never in the deposit. Null for Stripe and when none.","anyOf":[{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["count","amount"],"additionalProperties":false},{"type":"null"}]}},"required":["id","provider","date","settledOn","sentAt","status","watchingReason","amount","currency","paymentsCount","refundsCount","bankRef","bankLast4","bankName","batchName","otherAmount","shared","automatic","breakdown","notItemizedReason","movements","failure"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"po_1S9gB6AulkIu3Ep0payout01","provider":"stripe","date":"2026-10-08","status":"paid","watchingReason":null,"amount":6151,"currency":"USD","paymentsCount":1,"refundsCount":0,"bankRef":"20261008MMQFMPU8000123456","bankLast4":"6789","bankName":"STRIPE TEST BANK","batchName":null,"otherAmount":null,"shared":false,"automatic":true,"breakdown":{"provider":"stripe","charges":6500,"refunds":0,"stripeFees":219,"platformFees":130,"disputes":0,"other":0,"total":6151,"depositAmount":6151,"reconciled":true,"delta":0},"notItemizedReason":null,"movements":[{"paymentId":"7d0f1c1e-4a55-4d4c-9f1e-2b0c3e5a8f10","kind":"payment","customerName":"Ada Lovelace","item":"Wheel Throwing · Oct 10","amount":6500,"currency":"USD","cardBrand":"visa","cardLast4":"4242","occurredAt":"2026-10-04T16:02:11.000Z","reference":"txn_3S9fX1AulkIu3Ep0q1Kp8a2b"}],"failure":null},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/fees":{"get":{"operationId":"getFeesReport","summary":"A month's fees by kind, its sales, total, effective rate, rate history and rate by card type","description":"Stripe: the month's balance transactions — `fee_details` grouped by type (Stripe processing, tax on Stripe's fees, others by Stripe's description; our application fee as `booking_fee`, `party: platform`, apart from `total`), dispute fees, Stripe's account and FX fees — with counts and no rate (Stripe states none per charge); by card type is fee ÷ sales by funding and brand, `derived`. TRX: a stored statement's fee rows verbatim and its card plans with TRX's stated rates; \"of which card networks\" only under the consistency rule (architecture/20 § Fees); a month with no statement has the card networks so far and `trx_fees` `on_statement` with no amount, `total` null and a gap. `effectiveRate` is total ÷ sales, `derived: true`, only for a complete month. `history` is up to twelve closed months, each both stored facts; a month not stored is absent. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"month","schema":{"description":"`YYYY-MM`; the last closed month when omitted; the running month is allowed and answers `open: true`.","type":"string"},"description":"`YYYY-MM`; the last closed month when omitted; the running month is allowed and answers `open: true`."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"]},"month":{"type":"string"},"open":{"type":"boolean"},"currency":{"type":"string"},"timezone":{"type":"string"},"sales":{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"source":{"type":"string","enum":["trx_statement","trx_sales","stripe_balance_transactions"]}},"required":["amount","count","source"],"additionalProperties":false},"lines":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Stripe: stripe_processing · booking_fee · stripe_fee_tax · stripe_fee_<type> · stripe_account_fee · stripe_fx_fee · dispute_fee · stripe_fee_on_<type>. TRX: trx_statement_fee (each statement fee row verbatim) · card_networks · trx_fees (on the statement still to come)."},"label":{"type":"string"},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unitAmount":{"description":"TRX: the statement fee's per-item Amount, as stated.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rate":{"description":"Only a rate the processor stated; never derived. Stripe states none.","type":"object","properties":{"stated":{"type":"boolean","const":true},"percent":{"anyOf":[{"type":"number"},{"type":"null"}]},"perItemMinor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["stated","percent","perItemMinor"],"additionalProperties":false},"party":{"type":"string","enum":["processor","platform"]},"state":{"type":"string","enum":["stated","so_far","on_statement"]},"statementMonth":{"type":"string"}},"required":["kind","label","amount","party","state"],"additionalProperties":false}},"total":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bookingFees":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"effectiveRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"derived":{"type":"boolean","const":true},"effectiveRateNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardNetworks":{"anyOf":[{"type":"object","properties":{"label":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"saleCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["label","amount","saleCount"],"additionalProperties":false},{"type":"null"}]},"cardNetworksNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"sharedAccount":{"type":"boolean"},"sharedAccountNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"byCardType":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","enum":["card_plan","funding","brand"]},"key":{"type":"string"},"label":{"type":"string"},"saleAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"saleCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"creditAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"creditCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"netSaleAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"discountRatePercent":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountRateItem":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"discountTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"derived":{"type":"boolean"}},"required":["group","key","label","saleAmount","saleCount","derived"],"additionalProperties":false}},"byCardTypeNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"history":{"type":"array","items":{"type":"object","properties":{"month":{"type":"string"},"sales":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"derived":{"type":"boolean","const":true},"sharedAccount":{"type":"boolean"}},"required":["month","sales","fees","effectiveRate","derived"],"additionalProperties":false}},"gaps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["trx_fees_on_statement","card_networks_missing_detail","stripe_not_read_through","trx_ledger_unavailable","trx_ledger_not_read_for_month"]},"label":{"type":"string"},"month":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["key","label"],"additionalProperties":false,"description":"A figure the processor has not stated for this read, said in words instead of guessed."}},"statementDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"asOf":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["provider","month","open","currency","timezone","sales","lines","total","bookingFees","effectiveRate","derived","effectiveRateNote","cardNetworks","cardNetworksNote","sharedAccount","sharedAccountNote","byCardType","byCardTypeNote","history","gaps","statementDate","asOf"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"provider":"trx","month":"2026-09","open":false,"currency":"USD","timezone":"America/Los_Angeles","sales":{"amount":210000,"count":40,"source":"trx_statement"},"lines":[{"kind":"trx_statement_fee","label":"Monthly service fee","amount":1500,"count":1,"unitAmount":1500,"party":"processor","state":"stated"},{"kind":"trx_statement_fee","label":"Transaction fee","amount":3350,"count":67,"unitAmount":50,"party":"processor","state":"stated"}],"total":4850,"bookingFees":null,"effectiveRate":0.023095,"derived":true,"effectiveRateNote":null,"cardNetworks":null,"cardNetworksNote":"TRX's ledger for the month isn't available, so whether the card networks were billed on this statement can't be told.","sharedAccount":false,"sharedAccountNote":null,"byCardType":[{"group":"card_plan","key":"VISA","label":"Visa","saleAmount":210000,"saleCount":40,"creditAmount":6000,"creditCount":2,"netSaleAmount":204000,"discountRatePercent":2.65,"discountRateItem":10,"discountTotal":5806,"derived":false}],"byCardTypeNote":null,"history":[{"month":"2026-09","sales":210000,"fees":4850,"effectiveRate":0.023095,"derived":true},{"month":"2026-08","sales":188000,"fees":4610,"effectiveRate":0.024521,"derived":true}],"gaps":[],"statementDate":"2026-09-30","asOf":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/statements":{"get":{"operationId":"listStatements","summary":"The months a statement can be read for","description":"TRX: every stored TRX statement. Stripe: every closed month with stored balance transactions or payouts that the settlement sync has read past — generated from them on read. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"]},"statements":{"type":"array","items":{"type":"object","properties":{"month":{"type":"string"},"source":{"type":"string","enum":["trx_statement","stripe_balance_transactions"]},"statementDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"feeTotal":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"currency":{"type":"string"}},"required":["month","source","statementDate","feeTotal","currency"],"additionalProperties":false}}},"required":["provider","statements"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"provider":"stripe","statements":[{"month":"2026-09","source":"stripe_balance_transactions","statementDate":null,"feeTotal":null,"currency":"USD"},{"month":"2026-08","source":"stripe_balance_transactions","statementDate":null,"feeTotal":null,"currency":"USD"}]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/statements/{month}":{"get":{"operationId":"getStatement","summary":"A closed month's statement: deposits, withdrawals, chargebacks, reserves, fees, brands, totals","description":"TRX: the statement's deposits (joined to a batch only by an exactly equal deposit reference), the ledger's withdrawals (MerchantFees, DailyDiscount*, DailyInterchange*, Reserves, Chargebacks, Adjustments, …) or `null` with a gap when TRX's ledger is not available, the cases received, the card plans. Stripe: generated from the stored balance transactions and payouts — payouts that arrived, a negative payout as the one withdrawal, `withdrawalsNote` saying Stripe takes its fees inside payouts, dispute balance transactions with their case. `totals` only from the listed deposits and withdrawals. The running month is 400; a month with no statement 404. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/StatementMonthParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"]},"month":{"type":"string"},"source":{"type":"string","enum":["trx_statement","stripe_balance_transactions"]},"generatedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"asOf":{"anyOf":[{"type":"string"},{"type":"null"}]},"statementDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"type":"string"},"deposits":{"type":"array","items":{"type":"object","properties":{"date":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"bankRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"depositId":{"anyOf":[{"type":"string"},{"type":"null"}]},"oursAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"otherAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["date","amount","currency","bankRef","bankLast4","depositId"],"additionalProperties":false}},"withdrawals":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"date":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"category":{"type":"string"},"label":{"type":"string"},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankLast4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["date","amount","currency","category","label","reference","bankLast4"],"additionalProperties":false}},{"type":"null"}]},"withdrawalsNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"chargebacks":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fee":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"currency":{"type":"string"},"reference":{"type":"string"},"kind":{"type":"string","enum":["dispute","dispute_reversal","case"]},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["date","amount","fee","currency","reference","kind","reason","state","paymentId"],"additionalProperties":false}},"reserves":{"anyOf":[{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"date":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"category":{"type":"string"},"label":{"type":"string"},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankLast4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["date","amount","currency","category","label","reference","bankLast4"],"additionalProperties":false}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["rows","total"],"additionalProperties":false},{"type":"null"}]},"fees":{"type":"object","properties":{"lines":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Stripe: stripe_processing · booking_fee · stripe_fee_tax · stripe_fee_<type> · stripe_account_fee · stripe_fx_fee · dispute_fee · stripe_fee_on_<type>. TRX: trx_statement_fee (each statement fee row verbatim) · card_networks · trx_fees (on the statement still to come)."},"label":{"type":"string"},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unitAmount":{"description":"TRX: the statement fee's per-item Amount, as stated.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rate":{"description":"Only a rate the processor stated; never derived. Stripe states none.","type":"object","properties":{"stated":{"type":"boolean","const":true},"percent":{"anyOf":[{"type":"number"},{"type":"null"}]},"perItemMinor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["stated","percent","perItemMinor"],"additionalProperties":false},"party":{"type":"string","enum":["processor","platform"]},"state":{"type":"string","enum":["stated","so_far","on_statement"]},"statementMonth":{"type":"string"}},"required":["kind","label","amount","party","state"],"additionalProperties":false}},"total":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["lines","total"],"additionalProperties":false},"totals":{"type":"object","properties":{"depositedIn":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"takenOut":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"net":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["depositedIn","takenOut","net"],"additionalProperties":false},"byBrand":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","enum":["card_plan","funding","brand"]},"key":{"type":"string"},"label":{"type":"string"},"saleAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"saleCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"creditAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"creditCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"netSaleAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"discountRatePercent":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountRateItem":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"discountTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"derived":{"type":"boolean"}},"required":["group","key","label","saleAmount","saleCount","derived"],"additionalProperties":false}},"sharedAccount":{"type":"boolean"},"gaps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["trx_fees_on_statement","card_networks_missing_detail","stripe_not_read_through","trx_ledger_unavailable","trx_ledger_not_read_for_month"]},"label":{"type":"string"},"month":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["key","label"],"additionalProperties":false,"description":"A figure the processor has not stated for this read, said in words instead of guessed."}}},"required":["provider","month","source","generatedAt","asOf","statementDate","currency","deposits","withdrawals","withdrawalsNote","chargebacks","reserves","fees","totals","byBrand","sharedAccount","gaps"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"provider":"trx","month":"2026-09","source":"trx_statement","generatedAt":null,"asOf":null,"statementDate":"2026-09-30","currency":"USD","deposits":[{"date":"2026-09-26","amount":8000,"currency":"USD","bankRef":"900012345","bankLast4":"6789","depositId":"BATCH00000000A7"}],"withdrawals":[{"date":"2026-09-02","amount":-4610,"currency":"USD","category":"MerchantFees","label":"TRX fees","reference":"900012400","bankLast4":"6789"}],"withdrawalsNote":null,"chargebacks":[{"date":"2026-09-30","amount":3000,"fee":null,"currency":"USD","reference":"CB2026092600123","kind":"case","reason":"10.4 Other Fraud - Card Absent Environment","state":"open","paymentId":"7d0f1c1e-4a55-4d4c-9f1e-2b0c3e5a8f10"}],"reserves":{"rows":[],"total":0},"fees":{"lines":[{"kind":"trx_statement_fee","label":"Monthly service fee","amount":1500,"count":1,"unitAmount":1500,"party":"processor","state":"stated"},{"kind":"trx_statement_fee","label":"Transaction fee","amount":3350,"count":67,"unitAmount":50,"party":"processor","state":"stated"}],"total":4850},"totals":{"depositedIn":8000,"takenOut":-4610,"net":3390},"byBrand":[{"group":"card_plan","key":"VISA","label":"Visa","saleAmount":210000,"saleCount":40,"creditAmount":6000,"creditCount":2,"netSaleAmount":204000,"discountRatePercent":2.65,"discountRateItem":10,"discountTotal":5806,"derived":false}],"sharedAccount":false,"gaps":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/statements/{month}/export":{"get":{"operationId":"exportStatementCsv","summary":"Export a month's statement as CSV","description":"Columns `section,date,description,reference,last_four,count,amount,total,currency`. TRX: TRX's own statement rows first, byte-for-byte the `GET …/payments/statements/{date}?csv=1` body, then withdrawals, chargebacks, totals and notes. Stripe: deposits, card brands, fees, total fees, withdrawals, chargebacks, totals and the fees-inside-payouts note. Requires feature `finance.export`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/StatementMonthParam"}],"responses":{"200":{"description":"CSV file contents","content":{"text/csv":{"schema":{"type":"string"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/balance":{"get":{"operationId":"getPaymentsBalance","summary":"What the processor holds now and where it goes","description":"Stripe: the live available and pending balance, the payout bank and the payout schedule. TRX: the deposit account's last four as TRX stated it on a deposit and what is not yet deposited; TRX's deposit schedule is set at boarding and not stored, so it is a `gaps` entry. `finance.view` — a manager reads it. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"]},"currency":{"type":"string"},"available":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"pending":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bank":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"type":"string"}},"required":["name","last4"],"additionalProperties":false},{"type":"null"}]},"schedule":{"anyOf":[{"type":"object","properties":{"interval":{"type":"string"},"delayDays":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"weeklyAnchor":{"anyOf":[{"type":"string"},{"type":"null"}]},"monthlyAnchor":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["interval","delayDays","weeklyAnchor","monthlyAnchor"],"additionalProperties":false},{"type":"null"}]},"notYetDeposited":{"anyOf":[{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["count","amount"],"additionalProperties":false},{"type":"null"}]},"gaps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["stripe_unreachable","stripe_not_connected","deposit_interval_not_stored","deposit_account_not_stated"]},"label":{"type":"string"}},"required":["key","label"],"additionalProperties":false}}},"required":["provider","currency","available","pending","bank","schedule","notYetDeposited","gaps"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"provider":"stripe","currency":"USD","available":12500,"pending":6151,"bank":{"name":"STRIPE TEST BANK","last4":"6789"},"schedule":{"interval":"daily","delayDays":2,"weeklyAnchor":null,"monthlyAnchor":null},"notYetDeposited":null,"gaps":[]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/payouts/{payoutId}/transactions":{"get":{"operationId":"getPayoutTransactions","summary":"Transaction lines for one Stripe payout","description":"Transaction lines that settled in one Stripe payout. `payoutId` is the Stripe payout id (`po_…`). Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PayoutIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"timezone":{"type":"string"},"basis":{"type":"string","const":"cash"}},"required":["from","to","timezone","basis"],"additionalProperties":false},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"occurredAt":{"type":"string"},"localDate":{"type":"string"},"kind":{"type":"string"},"source":{"type":"string"},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerId":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardBrand":{"anyOf":[{"type":"string"},{"type":"null"}]},"depositRef":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The deposit this movement landed in: a Stripe payout id or a TRX batch GUID."},"depositDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"depositSettled":{"type":"boolean","description":"TRX: the batch is settled. With no depositDate it is settled and not yet deposited."},"bookingReference":{"anyOf":[{"type":"string"},{"type":"null"}]},"listingName":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringType":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Listing type on a booking row. Prefer `soldKind`. Kept so existing clients keep working.","deprecated":true},"soldKind":{"anyOf":[{"type":"string","enum":["class","session","space","membership","product"]},{"type":"null"}],"description":"What this allocation sold — the Transactions sold-kind column."},"quantity":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Set on product rows only. Bookings keep spots as a separate noun."},"sessionDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"gross":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"tax":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingFee":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"bookingId":{"anyOf":[{"type":"string"},{"type":"null"}]},"orderLineId":{"anyOf":[{"type":"string"},{"type":"null"}]},"stripePaymentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"trxReference":{"anyOf":[{"type":"string"},{"type":"null"}]},"memo":{"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"type":"string"},"refundReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"voided":{"type":"boolean","description":"A refund row that was a TRX void (the sale cancelled before its batch closed)."}},"required":["id","occurredAt","localDate","kind","source","customerName","customerId","cardLast4","cardBrand","depositRef","depositDate","depositSettled","bookingReference","listingName","offeringType","soldKind","quantity","sessionDate","gross","tax","bookingFee","currency","locationName","paymentId","bookingId","orderLineId","stripePaymentId","trxReference","memo","category","refundReason","voided"],"additionalProperties":false}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]},"stripeConnected":{"type":"boolean"},"unmatchedStripe":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"occurredAt":{"type":"string"},"localDate":{"type":"string"},"type":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fee":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"net":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"stripePaymentId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","occurredAt","localDate","type","amount","fee","net","currency","stripePaymentId"],"additionalProperties":false}},"settlementAsOf":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["period","rows","nextCursor","stripeConnected","unmatchedStripe","settlementAsOf"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/reports/payouts/{payoutId}/transactions/export":{"get":{"operationId":"exportPayoutCsv","summary":"Export one payout's transaction lines as CSV","description":"Transaction lines that settled in one Stripe payout, plus `payout_id`, `payout_arrival_date`, `payout_amount`. Filename is `payout-{payoutId}-{arrivalDate}.csv`. Requires feature `finance.export`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/PayoutIdParam"},{"in":"query","name":"from","schema":{"type":"string"}},{"in":"query","name":"to","schema":{"type":"string"}},{"in":"query","name":"preset","schema":{"type":"string","enum":["this_week","last_week","this_month","last_month","this_quarter","last_quarter","this_year","last_year"]}},{"in":"query","name":"locationId","schema":{"$ref":"#/components/schemas/Uuid"}}],"responses":{"200":{"description":"CSV file contents","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/schedules":{"post":{"operationId":"createSchedule","summary":"Create a schedule","description":"Creates a recurring schedule with structured or raw RRULE input. Requires feature `catalog.manage`.","tags":["availability"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateScheduleBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Schedule"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440014","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Tuesday evenings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=TU;BYHOUR=18;BYMINUTE=0","startDate":"2026-01-06","until":null,"durationMinutes":90,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listSchedules","summary":"List schedules for a business","description":"Lists schedules for a business, optionally filtered by location. Requires feature `location.view`.","tags":["availability"],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Schedule"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":[{"id":"550e8400-e29b-41d4-a716-446655440014","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Tuesday evenings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=TU;BYHOUR=18;BYMINUTE=0","startDate":"2026-01-06","until":null,"durationMinutes":90,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/schedules/{id}":{"get":{"operationId":"getSchedule","summary":"Get a schedule","description":"Returns a schedule by ID. Requires feature `location.view`.","tags":["availability"],"parameters":[{"$ref":"#/components/parameters/ScheduleIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Schedule"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440014","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Tuesday evenings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=TU;BYHOUR=18;BYMINUTE=0","startDate":"2026-01-06","until":null,"durationMinutes":90,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateSchedule","summary":"Update a schedule","description":"Booked dates never move: editing the rule changes only what is not yet booked. A change that would leave a booked date off the rule — a weekday dropped, a time moved, `until` brought forward, the zone changed — answers `409 { code: \"stranded_dates\", dates }` and writes nothing until `strandedDates` says `keep` or `cancel` (build-plan/166). Requires feature `catalog.manage`.","tags":["availability"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ScheduleIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateScheduleBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Schedule"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440014","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Tuesday evenings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=TU;BYHOUR=18;BYMINUTE=0","startDate":"2026-01-06","until":null,"durationMinutes":90,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"v":"1234"}}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"deleteSchedule","summary":"Delete a schedule (not supported)","description":"Delete a schedule (not supported)","tags":["availability"],"parameters":[{"$ref":"#/components/parameters/ScheduleIdParam"}],"responses":{"405":{"description":"Method not allowed — schedules are archived, not deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"code":{"type":"string","const":"method_not_allowed"}},"required":["code"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}}}}},"/schedules/{id}/archive":{"post":{"operationId":"archiveSchedule","summary":"Archive a schedule","description":"Soft-archives a schedule when no live offering references it. Requires feature `catalog.manage`.","tags":["availability"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/ScheduleIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Schedule"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"id":"550e8400-e29b-41d4-a716-446655440014","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Tuesday evenings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=TU;BYHOUR=18;BYMINUTE=0","startDate":"2026-01-06","until":null,"durationMinutes":90,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":"2026-07-24T12:00:00.000Z"},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/schedules/{id}/health":{"get":{"operationId":"getScheduleHealth","summary":"Validate that a schedule projects sane dates","description":"Validates a schedule projects sane, non-degenerate dates — catches bad RRULEs, zero duration, and timezone typos before they reach a customer. Requires feature `location.view`.","tags":["availability"],"parameters":[{"$ref":"#/components/parameters/ScheduleIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ScheduleHealthReport"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/schedules/{id}/occurrences":{"get":{"operationId":"listScheduleOccurrences","summary":"Project schedule dates in a window","description":"Projects concrete dates and times for a schedule in a date window. Requires feature `location.view`.","tags":["availability"],"parameters":[{"$ref":"#/components/parameters/ScheduleIdParam"},{"in":"query","name":"from","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true},{"in":"query","name":"to","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ScheduleOccurrencesResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-connections":{"get":{"operationId":"getSocialConnection","summary":"A location’s Instagram and Facebook connection","description":"The Page and Instagram for one location, or none. Tokens are never returned. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"configured":{"type":"boolean"},"connection":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["active","needs_reauth","disconnected"]},"pageId":{"type":"string"},"pageName":{"type":"string"},"pageHasLocation":{"type":"boolean"},"igUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"igUsername":{"anyOf":[{"type":"string"},{"type":"null"}]},"igPictureUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","locationId","status","pageId","pageName","pageHasLocation","igUserId","igUsername","igPictureUrl","lastError"],"additionalProperties":false},{"type":"null"}]},"canConnect":{"type":"boolean"},"place":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["configured","connection","canConnect","place"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"chooseSocialPage","summary":"Keep the Page the owner picked","description":"Uses the connect attempt once and replaces any live connection at the location. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"attemptId":{"type":"string"},"pageId":{"type":"string"}},"required":["attemptId","pageId"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["active","needs_reauth","disconnected"]},"pageId":{"type":"string"},"pageName":{"type":"string"},"pageHasLocation":{"type":"boolean"},"igUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"igUsername":{"anyOf":[{"type":"string"},{"type":"null"}]},"igPictureUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","locationId","status","pageId","pageName","pageHasLocation","igUserId","igUsername","igPictureUrl","lastError"],"additionalProperties":false},"redirectTo":{"type":"string"}},"required":["connection","redirectTo"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-connections/bio-link":{"get":{"operationId":"getSocialBioLink","summary":"Instagram’s bio link","description":"The connected Instagram account’s `website` (null when none is set, or there is no Instagram), whether it is the location’s public page, and that page’s address. Read from Meta each time; nothing is stored, and the API cannot set it. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"website":{"anyOf":[{"type":"string"},{"type":"null"}]},"isStudioPage":{"type":"boolean"},"studioUrl":{"type":"string"}},"required":["website","isStudioPage","studioUrl"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-connections/start":{"post":{"operationId":"startSocialConnection","summary":"Start connecting Instagram and Facebook","description":"Returns Meta’s consent URL. The browser comes back to `/app/meta/callback`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"returnTo":{"type":"string"}},"required":["locationId","returnTo"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"authorizeUrl":{"type":"string"}},"required":["authorizeUrl"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-connections/{connectionId}":{"delete":{"operationId":"disconnectSocialConnection","summary":"Disconnect Instagram and Facebook","description":"Disconnect Instagram and Facebook Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"path","name":"connectionId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"disconnected":{"type":"boolean"}},"required":["disconnected"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/me/meta/complete":{"post":{"operationId":"completeSocialConnection","summary":"Finish Meta’s return and list Pages","description":"The console’s callback posts Meta’s code with its own session. The signed-in person must be the one who pressed Connect. Pages carry no tokens.","tags":["me"],"security":[{"sessionBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"state":{"type":"string"},"error":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","const":"redirect"},"redirectTo":{"type":"string"}},"required":["status","redirectTo"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","const":"pages"},"businessId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"attemptId":{"type":"string"},"returnTo":{"type":"string"},"pages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hasLocation":{"type":"boolean"},"instagramUsername":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","hasLocation","instagramUsername"],"additionalProperties":false}}},"required":["status","businessId","attemptId","returnTo","pages"],"additionalProperties":false}]},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-voice":{"get":{"operationId":"getSocialVoice","summary":"How the studio writes its posts","description":"The voice note and hashtag set the post words follow: learned from the studio’s own posts, or the default for its type. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"voice":{"type":"string"},"hashtags":{"type":"array","items":{"type":"string"}},"source":{"type":"string","enum":["default","learned"]},"learnedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["voice","hashtags","source","learnedAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"put":{"operationId":"putSocialVoice","summary":"Rewrite the studio’s voice","description":"The owner’s note (at most 300 characters; empty puts the default back) and hashtags (at most 10). Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"voice":{"anyOf":[{"type":"string"},{"type":"null"}]},"hashtags":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"voice":{"type":"string"},"hashtags":{"type":"array","items":{"type":"string"}},"source":{"type":"string","enum":["default","learned"]},"learnedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["voice","hashtags","source","learnedAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-connections/{connectionId}/learn-voice":{"post":{"operationId":"learnSocialVoice","summary":"Learn the studio’s voice again","description":"Reads the Page’s and the Instagram account’s last posts, keeps a note on how they are written and the hashtags used twice, and stores none of the posts. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"path","name":"connectionId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"voice":{"type":"string"},"hashtags":{"type":"array","items":{"type":"string"}},"source":{"type":"string","enum":["default","learned"]},"learnedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["voice","hashtags","source","learnedAt"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/preview":{"post":{"operationId":"previewSocialPost","summary":"Preview a social post","description":"The recipe for one subject — a class date, a listing, a series, a pass, or a week — plus the accounts it would reach and when a morning-of Story would go. Exactly one subject. `words` are written around the recipe’s (`facts`) in the studio’s voice, or are the facts when no model answers (`wordsSource`). Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"occurrenceId":{"type":"string"},"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"seriesId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"planId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"weekOf":{"type":"string"}},"required":["locationId"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"recipe":{"type":"object","properties":{"words":{"type":"string"},"text":{"type":"object","properties":{"instagram":{"type":"string"},"facebook":{"type":"string"}},"required":["instagram","facebook"],"additionalProperties":false},"formats":{"type":"object","properties":{"instagram":{"type":"array","items":{"type":"string","enum":["post","story"]}},"facebook":{"type":"array","items":{"type":"string","enum":["post","story"]}}},"required":["instagram","facebook"],"additionalProperties":false},"storyAt":{"type":"string","enum":["morning_of","same"]},"collaborators":{"type":"array","items":{"type":"string"}},"mentions":{"type":"array","items":{"type":"string"}},"link":{"type":"string"},"openDates":{"type":"array","items":{"type":"string"}},"locationTag":{"type":"boolean"},"photos":{"type":"array","items":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"url":{"type":"string"},"alt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["assetId","url","alt"],"additionalProperties":false}},"frames":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["date","every_week","starts","next_opening","open_today","open_dates","day","cover"]},"eyebrow":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"type":"string"},"lines":{"type":"array","items":{"type":"string"}},"chip":{"anyOf":[{"type":"string"},{"type":"null"}]},"overflow":{"anyOf":[{"type":"string"},{"type":"null"}]},"photo":{"anyOf":[{"type":"object","properties":{"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"url":{"type":"string"},"alt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["assetId","url","alt"],"additionalProperties":false},{"type":"null"}]}},"required":["kind","eyebrow","title","lines","chip","overflow","photo"],"additionalProperties":false}},"blocked":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string"},"message":{"type":"string"}},"required":["reason","message"],"additionalProperties":false},{"type":"null"}]}},"required":["words","text","formats","storyAt","collaborators","mentions","link","openDates","locationTag","photos","frames","blocked"],"additionalProperties":false},"words":{"type":"string"},"facts":{"type":"string"},"wordsSource":{"type":"string","enum":["ai","default"]},"blocked":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string"},"message":{"type":"string"}},"required":["reason","message"],"additionalProperties":false},{"type":"null"}]},"heading":{"type":"object","properties":{"kind":{"type":"string","enum":["occurrence","listing","series","week","plan"]},"title":{"type":"string"},"line":{"type":"string"}},"required":["kind","title","line"],"additionalProperties":false},"accounts":{"type":"object","properties":{"instagram":{"anyOf":[{"type":"object","properties":{"username":{"type":"string"}},"required":["username"],"additionalProperties":false},{"type":"null"}]},"facebook":{"anyOf":[{"type":"object","properties":{"pageName":{"type":"string"},"place":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["pageName","place"],"additionalProperties":false},{"type":"null"}]}},"required":["instagram","facebook"],"additionalProperties":false},"morningOf":{"anyOf":[{"type":"string"},{"type":"null"}]},"look":{"type":"string"},"facebookLinkCard":{"type":"boolean"},"card":{"anyOf":[{"type":"object","properties":{"title":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["title","description"],"additionalProperties":false},{"type":"null"}]}},"required":["recipe","words","facts","wordsSource","blocked","heading","accounts","morningOf","look","facebookLinkCard","card"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/words":{"post":{"operationId":"socialPostWords","summary":"Write the words of a social post again","description":"An opener and an ask around the subject’s facts, in the studio’s voice, with hashtags from its set. `avoid` lists openers already shown. The facts alone when no model answers. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"occurrenceId":{"type":"string"},"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"seriesId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"planId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"weekOf":{"type":"string"},"avoid":{"type":"array","items":{"type":"string"}}},"required":["locationId"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"words":{"type":"string"},"opener":{"anyOf":[{"type":"string"},{"type":"null"}]},"ask":{"anyOf":[{"type":"string"},{"type":"null"}]},"hashtags":{"type":"array","items":{"type":"string"}},"source":{"type":"string","enum":["ai","default"]}},"required":["words","opener","ask","hashtags","source"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/frame.jpg":{"get":{"operationId":"socialPostFrame","summary":"One typeset frame of a social post, drawn now","description":"A Story frame or a list slide for the subject, drawn from today’s facts in the studio’s Look. `index` picks the recipe’s frame; `slot` is story (9:16) or slide (4:5). Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"occurrenceId","schema":{"type":"string"}},{"in":"query","name":"offeringId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"seriesId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"planId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"weekOf","schema":{"type":"string"}},{"in":"query","name":"index","schema":{"type":"string"}},{"in":"query","name":"slot","schema":{"type":"string","enum":["story","slide"]}}],"responses":{"200":{"description":"The frame as JPEG","content":{"image/jpeg":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/card.jpg":{"get":{"operationId":"socialPostCard","summary":"The Facebook card a class date’s post will show","description":"The dated link card as Facebook’s crawler fetches it: the first photo, the name, the date and time, spots left, the price, drawn from today’s facts and cached by what draws it. 404 for a subject with no dated card (a class, a series, a room, a pass, a week), whose link post carries the page’s own picture. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"occurrenceId","schema":{"type":"string"}},{"in":"query","name":"offeringId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"seriesId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"planId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"in":"query","name":"weekOf","schema":{"type":"string"}}],"responses":{"200":{"description":"The card as JPEG","content":{"image/jpeg":{"schema":{"type":"string"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/suggestions":{"get":{"operationId":"listSocialSuggestions","summary":"Up next: what is worth posting today","description":"Ready-made posts for a location, picked by rules from its schedule: last spots, tomorrow, the week (Saturday to Monday), a series starting, a new class, open dates — one per rule, never the same listing twice, never a subject posted this week, five at most. Each row is a subject the create body takes, with the reason, the listing’s first photo and the networks it would reach. No model call. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"suggestions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"kind":{"type":"string","enum":["occurrence","listing","series","week"]},"moment":{"type":"string","enum":["last_spots","tomorrow","week","starting","new","open_dates"]},"subject":{"anyOf":[{"type":"object","properties":{"occurrenceId":{"type":"string"}},"required":["occurrenceId"],"additionalProperties":false},{"type":"object","properties":{"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["offeringId"],"additionalProperties":false},{"type":"object","properties":{"seriesId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["seriesId"],"additionalProperties":false},{"type":"object","properties":{"weekOf":{"type":"string"}},"required":["weekOf"],"additionalProperties":false}]},"offeringId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"title":{"type":"string"},"line":{"type":"string"},"reason":{"type":"string"},"photo":{"anyOf":[{"type":"object","properties":{"url":{"type":"string"},"alt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["url","alt"],"additionalProperties":false},{"type":"null"}]},"networks":{"type":"array","items":{"type":"string","enum":["instagram","facebook"]}}},"required":["key","kind","moment","subject","offeringId","title","line","reason","photo","networks"],"additionalProperties":false}}},"required":["suggestions"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts":{"post":{"operationId":"createSocialPost","summary":"Post to Instagram and Facebook","description":"Creates one target per ticked format. Now publishes in the request; `at` schedules. Photos are asset ids in order (the recipe’s when omitted). Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"occurrenceId":{"type":"string"},"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"seriesId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"planId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"weekOf":{"type":"string"},"caption":{"type":"string"},"draftCaption":{"anyOf":[{"type":"string"},{"type":"null"}]},"formats":{"type":"object","properties":{"instagram":{"type":"array","items":{"type":"string","enum":["post","story"]}},"facebook":{"type":"array","items":{"type":"string","enum":["post","story"]}}}},"photos":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"collaborators":{"type":"array","items":{"type":"string"}},"at":{"anyOf":[{"type":"string"},{"type":"null"}]},"storyAt":{"type":"string"}},"required":["locationId","caption","formats"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"post":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["id"],"additionalProperties":false},"targets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"post_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"network":{"type":"string","enum":["instagram","facebook"]},"format":{"type":"string","enum":["post","story","reel"]},"status":{"type":"string","enum":["pending","published","failed","canceled"]},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"permalink":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","post_id","network","format","status","external_id","permalink","error"],"additionalProperties":false}}},"required":["post","targets"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"get":{"operationId":"listSocialPosts","summary":"Scheduled and recent social posts","description":"Posts with a pending target, plus the last 30 days, newest first, each with its targets and who made it. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["occurrence","listing","series","week","plan"]},"title":{"type":"string"},"line":{"type":"string"},"createdAt":{"type":"string"},"createdVia":{"type":"string","enum":["console","ask","mcp"]},"createdBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"canceledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"clicks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidLabel":{"type":"string"},"targets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"network":{"type":"string","enum":["instagram","facebook"]},"format":{"type":"string","enum":["post","story","reel"]},"runAt":{"type":"string"},"status":{"type":"string","enum":["pending","published","failed","canceled"]},"permalink":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"publishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","network","format","runAt","status","permalink","error","publishedAt"],"additionalProperties":false}}},"required":["id","kind","title","line","createdAt","createdVia","createdBy","canceledAt","clicks","booked","paidMinor","paidLabel","targets"],"additionalProperties":false}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/{postId}":{"get":{"operationId":"getSocialPost","summary":"One social post","description":"The list’s row plus what the post says and when it goes: the subject as the create body takes it, the caption and the words it opened with, photos, formats, collaborators, `at` (the first feed target’s time) and `storyAt` (`same`, `morning_of` or the Story’s instant). Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"path","name":"postId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SocialPostDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"updateSocialPost","summary":"Edit a scheduled social post","description":"Changes only what the body names, while no target has gone out (409 after). The subject is fixed, so each short link keeps its code. New photos are cut again; a format added gets a target and a link, one dropped is canceled; a new `at` or `storyAt` moves the pending targets and their tasks. The block rule is checked as on create. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"path","name":"postId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"caption":{"type":"string"},"draftCaption":{"anyOf":[{"type":"string"},{"type":"null"}]},"photos":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"formats":{"type":"object","properties":{"instagram":{"type":"array","items":{"type":"string","enum":["post","story"]}},"facebook":{"type":"array","items":{"type":"string","enum":["post","story"]}}}},"collaborators":{"type":"array","items":{"type":"string"}},"at":{"anyOf":[{"type":"string"},{"type":"null"}]},"storyAt":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SocialPostDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/{postId}/cancel":{"post":{"operationId":"cancelSocialPost","summary":"Cancel a social post that has not gone out","description":"Cancels pending targets. A target that already published stays. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"path","name":"postId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"canceled":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["canceled"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-posts/{postId}/targets/{targetId}/retry":{"post":{"operationId":"retrySocialPost","summary":"Retry a social post that failed","description":"Requeues the target when the connection is active. A target that already published is not sent again. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"path","name":"postId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"path","name":"targetId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"post_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"network":{"type":"string","enum":["instagram","facebook"]},"format":{"type":"string","enum":["post","story","reel"]},"status":{"type":"string","enum":["pending","published","failed","canceled"]},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"permalink":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","post_id","network","format","status","external_id","permalink","error"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/social-results":{"get":{"operationId":"getSocialResults","summary":"What a month of social posts brought","description":"Posts whose first target went out in `month` (YYYY-MM, the location’s time zone; this month when omitted), each with its short links’ clicks, the booked bookings that came through them and what those paid, and the month’s totals. Money is minor units with a label. Requires feature `catalog.manage`. Requires feature `catalog.manage`.","tags":["business"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"in":"path","name":"businessId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"locationId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},{"in":"query","name":"month","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"month":{"type":"string"},"posts":{"type":"array","items":{"type":"object","properties":{"postId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"title":{"type":"string"},"line":{"type":"string"},"publishedAt":{"type":"string"},"clicks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidLabel":{"type":"string"}},"required":["postId","title","line","publishedAt","clicks","booked","paidMinor","paidLabel"],"additionalProperties":false}},"totals":{"type":"object","properties":{"posts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"clicks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidLabel":{"type":"string"}},"required":["posts","clicks","booked","paidMinor","paidLabel"],"additionalProperties":false}},"required":["month","posts","totals"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/bookings/{bookingId}/pieces":{"get":{"operationId":"getStorefrontBookingPieces","summary":"Get a booking's pieces by manage link","description":"The pieces the booking holds, where each one is, and when each stage was reached — never the shelf. `canAdd` says whether the customer may photograph their own now.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerBookingPieces"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"addStorefrontBookingPiece","summary":"Add a piece from the booking page","description":"The customer photographs their own: one piece of 1–5 photos at Made, added by the customer. Open on a pieces listing's confirmed or checked-in booking from its session's start until the studio moves a piece past Made; otherwise 409, as is a booking already holding twelve pieces a spot.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/AddCustomerPieceBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerPiece"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/storefront/bookings/{bookingId}/pieces/{pieceId}":{"delete":{"operationId":"removeStorefrontBookingPiece","summary":"Take back a piece from the booking page","description":"A piece the customer added, while Add your pieces is open. The studio's pieces are 403; once a piece is past Made, 409.","tags":["storefront"],"parameters":[{"$ref":"#/components/parameters/BookingIdParam"},{"$ref":"#/components/parameters/PieceIdParam"}],"responses":{"204":{"description":"Removed"},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/terminals":{"get":{"operationId":"listTerminals","summary":"List terminals","description":"Live terminals only; a revoked one is gone from every read. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Terminal"}},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createTerminal","summary":"Add a terminal","description":"Returns the pairing code once. The device opens `pairing.url` (the QR) or types `pairing.code`. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["locationId"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TerminalWithPairing"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/terminals/{terminalId}":{"patch":{"operationId":"renameTerminal","summary":"Rename a terminal","description":"Rename a terminal Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"path","name":"terminalId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Terminal"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/terminals/{terminalId}/pairing-code":{"post":{"operationId":"newTerminalPairingCode","summary":"A fresh pairing code","description":"Only for a terminal that has not paired; 409 once it has — revoke it and add it again. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"path","name":"terminalId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TerminalWithPairing"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/terminals/{terminalId}/revoke":{"post":{"operationId":"revokeTerminal","summary":"Revoke a terminal","description":"Ends the device credential and every session it opened, together. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"path","name":"terminalId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"revoked":{"type":"boolean","const":true}},"required":["revoked"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/team/{personId}/pin":{"post":{"operationId":"giveTeamMemberPin","summary":"Give a team member a terminal PIN","description":"Issues a random four-digit PIN, unique in the business, and returns it once. A new one replaces the old. A PIN works only on a paired terminal. Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"path","name":"personId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"pin":{"type":"string"}},"required":["pin"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"delete":{"operationId":"removeTeamMemberPin","summary":"Remove a team member’s terminal PIN","description":"Remove a team member’s terminal PIN Requires feature `team.manage`.","tags":["access"],"security":[{"sessionBearer":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"in":"path","name":"personId","schema":{"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"removed":{"type":"boolean","const":true}},"required":["removed"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/terminal/pair":{"post":{"operationId":"pairTerminal","summary":"Pair this device as a terminal","description":"Trades a one-use pairing code for the device credential. 404 for a code that is wrong, used or expired.","tags":["access"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TerminalPaired"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/terminal/me":{"get":{"operationId":"getTerminalIdentity","summary":"Where this terminal is paired","description":"Presents the `bt_` device credential as the bearer. 401 `terminal_unpaired` once revoked.","tags":["access"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TerminalIdentity"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}}}}},"/terminal/sign-in":{"post":{"operationId":"terminalSignIn","summary":"Sign in on a terminal with a PIN","description":"Presents the `bt_` device credential as the bearer and a team member’s PIN in the body. 401 `wrong_pin` carries `attemptsLeft`; five wrong PINs in fifteen minutes is a 429 for that terminal.","tags":["access"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pin":{"type":"string"}},"required":["pin"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TerminalSignedIn"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/payouts":{"get":{"operationId":"listTrxPayouts","summary":"TRX batches as the studio's payouts, and what is not yet deposited","description":"One row per TRX batch, newest deposit first, with a status derived from the settlement facts — batching · settled · deposit_expected · watching (with its reason) — how many payments, and whether TRX's net matches our books. `notYetDeposited` is the approved sales still waiting and their sum. A Stripe business answers 409 `not_available_on_provider`; Stripe has its own payouts surface. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxPayoutList"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"payouts":[{"batchGuid":"BATCH0000000000A","status":"deposited","watchingReason":null,"batchStatus":"settled","amount":124000,"oursAmount":124000,"otherAmount":null,"shared":false,"currency":"USD","depositDate":"2026-09-26","openedAt":"2026-09-25T07:00:00.000Z","settledAt":"2026-09-26T07:12:00.000Z","paymentCount":14,"refundCount":1,"reconciled":true,"reconcileDelta":0},{"batchGuid":"BATCH0000000000B","status":"watching","watchingReason":"unreconciled","batchStatus":"settled","amount":51500,"oursAmount":51465,"otherAmount":null,"shared":false,"currency":"USD","depositDate":"2026-09-27","openedAt":"2026-09-25T07:00:00.000Z","settledAt":"2026-09-26T07:12:00.000Z","paymentCount":3,"refundCount":0,"reconciled":false,"reconcileDelta":35}],"notYetDeposited":{"count":2,"amount":41200,"currency":"USD"}},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/payouts/{batchGuid}":{"get":{"operationId":"getTrxPayout","summary":"One TRX batch with its sales, returns and adjustments — the Deposit receipt","description":"The batch row plus every sale and return of ours in it and any adjustment a platform admin attributed to it (a chargeback, recorded by hand — TRX has no dispute feed), with the total. A Stripe business answers 409 `not_available_on_provider`; Stripe has its own payouts surface. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/TrxBatchGuidParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxPayoutDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"batchGuid":"BATCH0000000000A","status":"deposited","watchingReason":null,"batchStatus":"settled","amount":124000,"oursAmount":124000,"otherAmount":null,"shared":false,"currency":"USD","depositDate":"2026-09-26","openedAt":"2026-09-25T07:00:00.000Z","settledAt":"2026-09-26T07:12:00.000Z","paymentCount":14,"refundCount":1,"reconciled":true,"reconcileDelta":0,"payments":[{"reference":"SALE00000000001","kind":"sale","paymentId":"550e8400-e29b-41d4-a716-446655440009","customerName":"F. HOLT","item":"Wheel Basics · Sep 25","amount":5000,"currency":"USD","cardBrand":"Visa","cardLast4":"4242","createdAt":"2026-09-25T15:04:00.000Z","depositDate":"2026-09-26"}],"refunds":[{"reference":"RET000000000001","kind":"return","paymentId":"550e8400-e29b-41d4-a716-446655440009","customerName":"F. HOLT","item":"Wheel Basics · Sep 25","amount":500,"currency":"USD","cardBrand":"Visa","cardLast4":"4242","createdAt":"2026-09-25T16:10:00.000Z","depositDate":"2026-09-26"}],"adjustments":[],"total":4500},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/statements":{"get":{"operationId":"listTrxStatements","summary":"The monthly TRX statements fetched for this business","description":"Newest first: statement date, client, DBA, the fee total TRX billed from the fee account, how many deposits it lists, and whether the fees are in the journal. A Stripe business answers 409 `not_available_on_provider`; Stripe has its own payouts surface. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxStatementList"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"statements":[{"statementDate":"2026-08-31","clientId":"412","dba":"Ash Street Yoga","feeTotal":4850,"currency":"USD","depositCount":21,"journaled":true,"journalSkipReason":null}]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/businesses/{businessId}/payments/statements/{statementDate}":{"get":{"operationId":"getTrxStatement","summary":"One monthly TRX statement — deposits, card plans and the fee table","description":"The statement as TRX gave it: deposits by reference number, card plans, and the fees with their counts, amounts and totals. `?csv=1` answers the same statement as a CSV body. A Stripe business answers 409 `not_available_on_provider`; Stripe has its own payouts surface. Requires feature `finance.view`.","tags":["commerce"],"security":[{"sessionBearer":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BusinessIdParam"},{"$ref":"#/components/parameters/TrxStatementDateParam"},{"in":"query","name":"csv","schema":{"description":"Answer a CSV body instead of JSON","type":"string","enum":["1","true"]},"description":"Answer a CSV body instead of JSON"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TrxStatementDetail"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope","example":{"data":{"statementDate":"2026-08-31","clientId":"412","dba":"Ash Street Yoga","feeTotal":4850,"currency":"USD","depositCount":21,"journaled":true,"journalSkipReason":null,"deposits":[{"tranDate":"2026-08-03","approvedAmount":124000,"lastFour":"4242","referenceNumber":"900012345"}],"cardPlans":[{"planCode":"VISA","saleCount":40,"saleAmount":210000,"creditCount":2,"creditAmount":6000,"netSaleAmount":204000,"averageTicket":5250,"discountRatePercent":2.65,"discountRateItem":10,"discountTotal":5806}],"fees":[{"description":"Monthly service fee","count":1,"amount":1500,"total":1500},{"description":"Transaction fee","count":67,"amount":50,"total":3350}]},"v":"1234"}}}}},"401":{"description":"Authentication required (`unauthorized`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Insufficient permissions (`forbidden`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (`conflict`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/waitlist":{"post":{"operationId":"joinSignupWaitlist","summary":"Join the coming-soon waitlist","description":"The landing page’s waitlist form while the platform is closed to new studios. One row per email: a repeat is a quiet success with the same answer, so the endpoint never says who else has joined. No email is sent. A form post (`application/x-www-form-urlencoded`) is answered with a 303 back to the landing page. Returns 404 when coming-soon mode is off.","tags":["system"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupWaitlistBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignupWaitlistResult"},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["data","v"],"additionalProperties":false,"description":"Success response envelope"}}}},"400":{"description":"Validation error (`validation`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Resource not found (`not_found`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (`too_many_requests`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}},"components":{"schemas":{"Uuid":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID identifier","example":"550e8400-e29b-41d4-a716-446655440000"},"AgreementBody":{"type":"object","properties":{"name":{"type":"string"},"everyListing":{"description":"On every listing at the location (default true on create). Flipping it adds it to, or takes it off, every listing.","type":"boolean"},"show":{"type":"string","enum":["list","popup","full"]},"frequency":{"type":"string","enum":["once","every_booking"]},"body":{"description":"Markdown: headings, lists, **bold**. Send this or a multipart `file` (PDF, 10 MB).","type":"string"},"reask":{"description":"On update, when the words or file change: ask everyone who agreed to agree again.","type":"boolean"}},"example":{"name":"Liability waiver","body":"I take part at my own risk.","everyListing":true,"show":"list","frequency":"once"}},"UploadImageBody":{"type":"object","properties":{"file":{"type":"string","description":"Image file (JPEG, PNG, or WebP)","format":"binary"}},"required":["file"],"example":{"file":"(binary)"}},"UpdateAssetBody":{"type":"object","properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"altText":{"anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string"}}},"example":{"altText":"Hands shaping clay","tags":["studio"]}},"AttachAssetBody":{"type":"object","properties":{"assetId":{"$ref":"#/components/schemas/Uuid"}},"required":["assetId"],"example":{"assetId":"550e8400-e29b-41d4-a716-446655440019"}},"BookingImportTimeMapping":{"type":"object","properties":{"zone":{"type":"string","description":"IANA zone for times that name none (Times are in)."},"dayFirst":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Day/month order; null lets the column decide."},"format":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A pattern from the known list, tried first; null for none."}},"required":["zone","dayFirst","format"]},"BookingImportRow":{"type":"object","properties":{"row":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"The row’s index in the file."},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"},"description":"Raw cell text by field, blanks left out."},"notes":{"description":"The Notes columns in the file’s order (D11).","type":"array","items":{"type":"object","properties":{"column":{"type":"string"},"value":{"type":"string"}},"required":["column","value"]}},"raw":{"description":"The row as it was in the file — kept on a question for Download rows that need you.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["row","fields"]},"CreateBusinessBody":{"type":"object","properties":{"name":{"type":"string"},"contactEmail":{"$ref":"#/components/schemas/Email"},"businessType":{"$ref":"#/components/schemas/BusinessType"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"url":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"$ref":"#/components/schemas/CurrencyCode"},"locale":{"$ref":"#/components/schemas/Locale"},"dateFormat":{"$ref":"#/components/schemas/DateFormat"},"location":{"type":"object","properties":{"name":{"type":"string","example":"Downtown Studio"},"address":{"type":"string","example":"123 Main St, Denver, CO"},"timezone":{"type":"string","example":"America/Denver","description":"IANA timezone identifier"},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactEmail":{"anyOf":[{"$ref":"#/components/schemas/Email"},{"type":"null"}]},"defaultConfirmationMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultClassDurationMinutes":{"description":"How long a new class runs, in minutes.","example":60,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"defaultAppointmentDurationMinutes":{"description":"How long a new reservation runs, in minutes.","example":60,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","address","timezone"]},"legalGivenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalFamilyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalName":{"description":"Full name from the single intake field — split into given/family server-side when the split fields are absent","anyOf":[{"type":"string"},{"type":"null"}]},"acceptedLegal":{"type":"boolean","const":true},"legalSurface":{"type":"string","enum":["get_started","setup_agent","setup_form"]},"enabledModules":{"description":"The sections the studio starts with (the first-run form sends its type defaults). Omitted: none yet.","type":"array","items":{"type":"string","enum":["classes","sessions","spaces","memberships","products"]}}},"required":["name","contactEmail","businessType","location"],"example":{"name":"Sunrise Studio","contactEmail":"hello@sunrise.example.com","businessType":"art_maker","currency":"USD","locale":"en-US","dateFormat":"MDY","location":{"name":"Downtown Studio","address":"123 Main St, Denver, CO","timezone":"America/Denver"},"acceptedLegal":true}},"Email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"Email address","example":"alex@example.com"},"BusinessType":{"type":"string","enum":["fitness_movement","art_maker","music_performance","wellness_bodywork","sports_recreation","venue_event_space","other"],"description":"Marketing taxonomy for what the business does. Required on create; null on legacy rows. Labels/hints come from GET /app-config. Not a routing field.","example":"art_maker"},"CurrencyCode":{"type":"string","enum":["AUD","CAD","CHF","DKK","EUR","GBP","INR","JPY","MXN","NOK","NZD","SEK","SGD","USD","ZAR"],"description":"ISO 4217. The business default — new listings and membership plans inherit it. Money already written keeps its own currency.","example":"USD"},"Locale":{"type":"string","description":"BCP 47 language tag. Drives number/currency display style only — not UI language. See architecture/15-locale.md.","example":"en-US"},"DateFormat":{"type":"string","enum":["MDY","DMY","YMD"],"description":"Display ordering for calendar dates (MDY/DMY/YMD). Never affects storage — timestamps are UTC and time-of-day belongs to the location timezone. See architecture/15-locale.md.","example":"MDY"},"UpdateBusinessBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"url":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactEmail":{"$ref":"#/components/schemas/Email"},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"accountantEmail":{"anyOf":[{"$ref":"#/components/schemas/Email"},{"type":"null"}]},"currency":{"$ref":"#/components/schemas/CurrencyCode"},"locale":{"$ref":"#/components/schemas/Locale"},"dateFormat":{"$ref":"#/components/schemas/DateFormat"},"businessType":{"$ref":"#/components/schemas/BusinessType"},"feeMode":{"type":"string","enum":["absorb","split","pass"]},"feeCustomerPct":{"type":"integer","minimum":0,"maximum":100},"enabledModules":{"type":"array","items":{"type":"string","enum":["classes","sessions","spaces","memberships","products"]}},"deskPaymentMethods":{"description":"PlaceFull's own ways the desk takes payment. Cash is not taken (architecture/05 § Cash) — a studio that takes it adds it as a payment method.","type":"array","items":{"type":"string","enum":["card","link"]}},"bookingHorizonDays":{"type":"integer","minimum":1,"maximum":730},"bookingCutoffMinutes":{"type":"integer","minimum":0,"maximum":525600},"cancellationCutoffHours":{"description":"Hours before start when cancelling closes; null or 0 = any time; -1 = no cancellation (customers cannot cancel online).","anyOf":[{"type":"integer","minimum":-1,"maximum":8760},{"type":"null"}]},"rescheduleCutoffHours":{"description":"Hours before start when changing the time closes; null or 0 = until the start; -1 = no changes (customers cannot move online).","anyOf":[{"type":"integer","minimum":-1,"maximum":8760},{"type":"null"}]},"spotsLeft":{"description":"Spots left on a storefront time: few (at five or fewer, once one is taken) or always (whenever a time has spots left). Listings follow it unless they set their own (build-plan/238).","type":"string","enum":["few","always"]},"bookingMessages":{"description":"How customers hear about their bookings. sms is refused where SMS is unconfigured.","type":"string","enum":["email","sms"]},"requireBookingPhone":{"description":"Settings → Booking → Contact. On, a booking checkout requires a phone number. Email is always required.","type":"boolean"},"guestMarketingConsentDefault":{"description":"Settings → Booking → Contact. On, guests see the news checkbox ticked at checkout. They can untick it. Default true.","type":"boolean"},"words":{"$ref":"#/components/schemas/StudioWords"},"messages":{"$ref":"#/components/schemas/BusinessMessagesPatch"}},"example":{"name":"Sunrise Studio LLC","accountantEmail":"books@sunrise.example.com","currency":"GBP","locale":"en-GB","dateFormat":"DMY","businessType":"fitness_movement","enabledModules":["instructors","spaces"],"bookingMessages":"email","words":{"instructor":"coach"}}},"StudioWords":{"type":"object","properties":{"instructor":{"description":"What customers see your instructors called. Default: instructor.","type":"string","enum":["instructor","coach","teacher","trainer","guide"]}},"example":{"instructor":"coach"}},"BusinessMessagesPatch":{"type":"object","properties":{"scheduleEmpty":{"anyOf":[{"type":"string","maxLength":120,"description":"Shown where the times would be."},{"type":"null"}]},"soldOut":{"anyOf":[{"type":"string","maxLength":200,"description":"Shown above the waitlist when the time they picked is full."},{"type":"null"}]},"passwordPrompt":{"anyOf":[{"type":"string","maxLength":160,"description":"The line above the password field on a listing with a password."},{"type":"null"}]},"newsOptIn":{"anyOf":[{"type":"string","maxLength":80,"description":"The checkbox under email at checkout."},{"type":"null"}]},"bookedHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"enrolledHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"payLinkHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"waitlistJoinedNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added after their place in line."},{"type":"null"}]},"waitlistOfferHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"waitlistOfferNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the offer. The deadline stays."},{"type":"null"}]},"waitlistMissedHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"waitlistMissedNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under our sentence."},{"type":"null"}]},"movedHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"movedNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the new time."},{"type":"null"}]},"canceledByStudioHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"canceledByStudioNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},{"type":"null"}]},"canceledByCustomerHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"canceledByCustomerNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},{"type":"null"}]},"enrollmentCanceledHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"enrollmentCanceledNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},{"type":"null"}]},"refundNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the amount, which stays."},{"type":"null"}]},"balanceNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the amount, which stays."},{"type":"null"}]},"membershipHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"membershipNote":{"anyOf":[{"type":"string","maxLength":300,"description":"A welcome under our sentence."},{"type":"null"}]},"membershipFailedNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under our sentence about the card."},{"type":"null"}]}},"example":{"soldOut":"We're so popular, it sold out!"}},"CreateBookingBody":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"$ref":"#/components/schemas/Uuid"},"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"channel":{"type":"string","enum":["online","staff","api"]},"redeemCredits":{"type":"boolean"},"idempotencyKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"paidElsewhere":{"anyOf":[{"type":"object","properties":{"channelId":{"$ref":"#/components/schemas/Uuid"},"reference":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["channelId"]},{"type":"null"}]},"overClosure":{"type":"boolean"}},"required":["offeringId","occurrenceId","customerId","partySize"],"example":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","customerId":"550e8400-e29b-41d4-a716-446655440006","partySize":1,"channel":"staff"}},"CreateOperatorCartBody":{"type":"object","properties":{"items":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/CartItemBody"}},"customerId":{"$ref":"#/components/schemas/Uuid"},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string","maxLength":200},"note":{"type":"string","maxLength":2000},"channel":{"type":"string","enum":["staff","api"]}},"required":["items"],"example":{"items":[{"offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","partySize":1}],"customerId":"550e8400-e29b-41d4-a716-446655440006","channel":"staff","note":"See you Tuesday!"}},"CartItemBody":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"subscribe":{"type":"boolean"},"membershipPlanId":{"$ref":"#/components/schemas/Uuid"},"seriesId":{"$ref":"#/components/schemas/Uuid"},"variantId":{"$ref":"#/components/schemas/Uuid"},"quantity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"locationId":{"$ref":"#/components/schemas/Uuid"},"bookingId":{"$ref":"#/components/schemas/Uuid"},"overClosure":{"description":"Desk and agent carts only (build-plan/249): book a start a closure covers. A customer cart is refused. Omitted keeps the closure.","type":"boolean"},"answers":{"description":"Booking, series and subscription lines: what was answered for this booking (build-plan/239) — the Book sheet, or the desk; a subscription's go on every session it holds. Checked for shape, never for Required; a value that is not an answer is a 400 and nothing is held. Omitted is not answered yet.","type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"]}]}},"required":["questionId","value"]}}},"example":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","partySize":1}},"LocationPagePreviewBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"type":"string"},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactEmail":{"anyOf":[{"type":"string"},{"type":"null"}]},"logoUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"logoShape":{"anyOf":[{"type":"string"},{"type":"null"}]},"ctaColor":{"anyOf":[{"type":"string"},{"type":"null"}]},"storefrontTheme":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"links":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"ListingPagePreviewBody":{"type":"object","properties":{"offeringId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"type":{"type":"string","enum":["class","session","space"]},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"level":{"anyOf":[{"type":"string"},{"type":"null"}]},"whatToBring":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"type":"integer","minimum":0,"maximum":9007199254740991},"capacity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"durationMinutes":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]}}},"PassesPagePreviewBody":{"type":"object","properties":{"planId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"type":"integer","minimum":0,"maximum":9007199254740991},"billingPeriod":{"type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"expiresAfterDays":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]},"benefits":{"type":"string"}}},"ConfirmBookingBody":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","manual","trx"]},"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["provider","expectedEffect"],"example":{"provider":"stripe","expectedEffect":{"currency":"USD","movements":[{"direction":"charge","instrument":"card","amount":5000}]}}},"ExpectedMoneyEffect":{"type":"object","properties":{"currency":{"type":"string","minLength":3,"maxLength":3},"movements":{"type":"array","items":{"type":"object","properties":{"direction":{"type":"string","enum":["charge","refund","forfeit"]},"instrument":{"type":"string","enum":["card","cash","credits"]},"amount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["direction","instrument","amount"]}}},"required":["currency","movements"],"example":{"currency":"USD","movements":[{"direction":"charge","instrument":"cash","amount":5000}]}},"CollectBalanceBody":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","manual","trx"]},"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["provider","expectedEffect"],"example":{"provider":"stripe","expectedEffect":{"currency":"USD","movements":[{"direction":"charge","instrument":"card","amount":5000}]}}},"RecordBookingPaymentBody":{"type":"object","properties":{"channelId":{"description":"The paid-elsewhere payment method it was paid through.","$ref":"#/components/schemas/Uuid"},"reference":{"description":"The other system's reference, as the method's rule asks (required, optional, or dropped).","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["channelId"],"example":{"channelId":"00000000-0000-4000-8000-0000000000c1","reference":"GRPN-8K2Q"}},"AddToBookingBody":{"type":"object","properties":{"pieces":{"minItems":1,"type":"array","items":{"type":"object","properties":{"variantId":{"$ref":"#/components/schemas/Uuid"},"quantity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["variantId","quantity"]}},"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["pieces","expectedEffect"],"example":{"pieces":[{"variantId":"0192f1a0-7c3d-7e10-9a2b-000000000031","quantity":1}],"expectedEffect":{"currency":"USD","movements":[{"direction":"charge","instrument":"card","amount":1308}]}}},"CancelBookingBody":{"type":"object","properties":{"reason":{"type":"string"},"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["expectedEffect"],"example":{"reason":"Schedule conflict","expectedEffect":{"currency":"USD","movements":[]}}},"ChangeBookingEmailBody":{"type":"object","properties":{"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"sendConfirmation":{"type":"boolean"},"preview":{"type":"boolean"}},"required":["email"],"example":{"email":"jane@gmail.com","name":"Jane Smith","sendConfirmation":true}},"RescheduleBookingBody":{"type":"object","properties":{"newOccurrenceId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"resourceId":{"$ref":"#/components/schemas/Uuid"},"tableId":{"$ref":"#/components/schemas/Uuid"},"overClosure":{"type":"boolean"}},"example":{"newOccurrenceId":"550e8400-e29b-41d4-a716-446655440013"}},"CheckInBookingBody":{"type":"object","properties":{"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["expectedEffect"],"example":{"expectedEffect":{"currency":"USD","movements":[]}}},"CheckInAtDeskBody":{"type":"object","properties":{"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"},"tableId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"endsAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"keepStart":{"description":"Early: keep the reserved start and mark them here — the window moves only for an end that changed. Without it an early check-in starts now.","type":"boolean"},"anyway":{"description":"Manual check-in only (build-plan/292): check in although the place is over — without it that is 409 over_capacity.","type":"boolean"}},"required":["expectedEffect"],"example":{"expectedEffect":{"currency":"USD","movements":[]}}},"CheckOutBookingBody":{"type":"object","properties":{"at":{"description":"When they left — between the start and now; omitted = now.","anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"example":{}},"MoveBookingPositionBody":{"type":"object","properties":{"fromPositionId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"toPositionId":{"$ref":"#/components/schemas/Uuid"}},"required":["toPositionId"],"example":{"fromPositionId":"550e8400-e29b-41d4-a716-446655440030","toPositionId":"550e8400-e29b-41d4-a716-446655440031"}},"OccurrenceMessageBody":{"type":"object","properties":{"subject":{"type":"string","minLength":1,"maxLength":200},"body":{"type":"string","minLength":1,"maxLength":8000},"channels":{"description":"How it goes out (build-plan/262): `email` to everyone booked, `wallet` as a note on their Wallet tickets — the subject as its title (60 characters) and the message as plain text (500) — or both. Default `[\"email\"]`.","minItems":1,"type":"array","items":{"type":"string","enum":["email","wallet"]}}},"required":["subject","body"],"example":{"subject":"Morning Flow · Monday, August 31, 10:00 AM","body":"Studio B today — use the side door."}},"WalletNoteBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":60,"description":"Shown as the note’s heading on the pass, and as the notification."},"body":{"type":"string","minLength":1,"maxLength":500,"description":"Plain text (Markdown is flattened), on the back of the pass."}},"required":["title","body"],"example":{"title":"Studio closed Monday","body":"We’re closed for the holiday. Classes resume Tuesday."}},"CreateChannelBody":{"type":"object","properties":{"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["door","pos","legacy","marketplace","venue","other"]},"icon":{"type":"string","enum":["ticket","store","receipt","gift","tag","globe","building","history"]},"referenceMode":{"type":"string","enum":["off","optional","required"]},"referenceLabel":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name"],"example":{"name":"Groupon","icon":"ticket","referenceMode":"required","referenceLabel":"Voucher code"}},"UpdateChannelBody":{"type":"object","properties":{"name":{"type":"string","minLength":1},"archived":{"type":"boolean"},"referenceLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"referencePattern":{"anyOf":[{"type":"string"},{"type":"null"}]},"referenceUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"enabled":{"type":"boolean"},"referenceMode":{"type":"string","enum":["off","optional","required"]},"icon":{"type":"string","enum":["ticket","store","receipt","gift","tag","globe","building","history"]}},"example":{"referenceLabel":"Square order #","referenceUrl":"https://squareup.com/dashboard/orders/overview/{ref}"}},"CreateClaimBody":{"type":"object","properties":{"channelId":{"$ref":"#/components/schemas/Uuid"},"channel":{"type":"object","properties":{"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["door","pos","legacy","marketplace","venue","other"]}},"required":["name"]},"seats":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"label":{"type":"string"},"externalRef":{"type":"string"},"note":{"type":"string"},"tableId":{"$ref":"#/components/schemas/Uuid"}},"required":["seats"],"example":{"channel":{"name":"Square","kind":"pos"},"seats":2}},"SyncClaimBody":{"type":"object","properties":{"occurrence":{"$ref":"#/components/schemas/OccurrenceAddress"},"seats":{"type":"integer","minimum":0,"maximum":9007199254740991},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["occurrence","seats"],"example":{"occurrence":{"offeringId":"550e8400-e29b-41d4-a716-446655440020","localStart":"2026-09-03T18:00"},"seats":2}},"OccurrenceAddress":{"type":"object","properties":{"occurrenceId":{"type":"string"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"listingSlug":{"type":"string"},"locationId":{"$ref":"#/components/schemas/Uuid"},"localStart":{"type":"string"}},"example":{"offeringId":"550e8400-e29b-41d4-a716-446655440020","localStart":"2026-09-03T18:00"}},"SyncClaimsBatchBody":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"occurrence":{"$ref":"#/components/schemas/OccurrenceAddress"},"seats":{"type":"integer","minimum":0,"maximum":9007199254740991},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalRef":{"type":"string","minLength":1}},"required":["occurrence","seats","externalRef"]}}},"required":["items"],"example":{"items":[{"externalRef":"sqr_123","occurrence":{"offeringId":"550e8400-e29b-41d4-a716-446655440020","localStart":"2026-09-03T18:00"},"seats":2}]}},"UpdateClaimBody":{"type":"object","properties":{"seats":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalRef":{"anyOf":[{"type":"string"},{"type":"null"}]}},"example":{"seats":1}},"UnlinkPaymentsAccountBody":{"type":"object","properties":{"reason":{"description":"Why — kept on the `business.payments_account.unlinked` event for the next admin.","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]}},"example":{"reason":"Studio moved to a new Stripe account"}},"ChoosePaymentsProviderBody":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"],"description":"trx makes the business a TRX business (fee bearer absorb, Passes off) and opens the application; stripe moves it back"}},"required":["provider"],"example":{"provider":"trx"}},"TrxApplicationDraftBody":{"type":"object","properties":{"business":{"type":"object","properties":{"legalName":{"type":"string"},"dba":{"type":"string"},"ownershipType":{"type":"string","enum":["SoleProprietor","LLC","Corporation","Partnership","NonProfit","Other"]},"established":{"type":"string","description":"YYYY-MM"},"phone":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"address":{"type":"string"},"address2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string","description":"Two-letter state"},"postal":{"type":"string"},"merchandise":{"type":"string","description":"What the business sells, ≤40 characters"}}},"owners":{"maxItems":2,"type":"array","items":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"ownershipPercent":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"}}}},"bank":{"type":"object","properties":{"accountType":{"type":"string","enum":["checking","savings"]},"holder":{"type":"string","enum":["business","personal"]},"feesSameAccount":{"type":"boolean"}}},"volumes":{"type":"object","properties":{"monthlyVolume":{"type":"string"},"dailyVolume":{"type":"string"},"averageTicket":{"type":"string"},"maximumTicket":{"type":"string"}}}},"description":"The non-sensitive half only, through an allowlist: an SSN, date of birth, licence, EIN, bank number or document sent here is dropped, never stored.","example":{"business":{"dba":"Ash Street Yoga","ownershipType":"LLC"},"owners":[{"firstName":"Avery","lastName":"Example","ownershipPercent":"100"}]}},"TrxApplicationSubmitBody":{"type":"object","properties":{"business":{"type":"object","properties":{"legalName":{"type":"string"},"dba":{"type":"string"},"ownershipType":{"type":"string","enum":["SoleProprietor","LLC","Corporation","Partnership","NonProfit","Other"]},"established":{"type":"string","description":"YYYY-MM"},"phone":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"address":{"type":"string"},"address2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string","description":"Two-letter state"},"postal":{"type":"string"},"merchandise":{"type":"string","description":"What the business sells, ≤40 characters"},"ein":{"type":"string","description":"EIN, 9 digits. Sent to TRX, never stored."}},"required":["ein"]},"owners":{"minItems":1,"maxItems":2,"type":"array","items":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"ownershipPercent":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"ssn":{"type":"string","description":"9 digits. Sent to TRX, never stored; the last four are kept"},"dateOfBirth":{"type":"string","description":"YYYY-MM-DD, 18 or older. Never stored"},"address":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"licenseNumber":{"type":"string","description":"Driver's licence, 7–20 characters. Never stored"},"licenseRegion":{"type":"string"},"licenseExpiration":{"type":"string","description":"YYYY-MM-DD, still valid"}},"required":["ssn","dateOfBirth","address","city","region","postal","licenseNumber","licenseRegion","licenseExpiration"]},"description":"The owner, and a second owner of 25% or more; together at most 100%"},"bank":{"type":"object","properties":{"accountType":{"type":"string","enum":["checking","savings"]},"holder":{"type":"string","enum":["business","personal"]},"routing":{"type":"string","description":"ABA routing number, checksum-checked. Never stored"},"account":{"type":"string","description":"4–17 digits. Never stored; the last four are kept"},"feesSameAccount":{"type":"boolean"},"feesRouting":{"type":"string"},"feesAccount":{"type":"string"}},"required":["accountType","holder","routing","account"]},"volumes":{"type":"object","properties":{"monthlyVolume":{"type":"string"},"dailyVolume":{"type":"string","description":"The biggest day of card sales: at least the average sale, at most the month"},"averageTicket":{"type":"string"},"maximumTicket":{"type":"string"}},"required":["monthlyVolume","dailyVolume","averageTicket","maximumTicket"],"description":"Dollars"},"documents":{"minItems":3,"maxItems":7,"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["id_front","id_back","id2_front","id2_back","voided_check","bank_letter","w9","ss4","application"],"description":"`application` is TRX’s merchant application, filled and signed in the browser and drawn as page images (a 5-page PDF); the server appends the electronic signature record page"},"fileName":{"description":"Ignored: TRX files it as id-owner1-front.jpg and the like","type":"string"},"contentType":{"description":"Ignored: the bytes say what they are — JPEG, PNG or PDF","type":"string"},"data":{"type":"string","maxLength":2097152,"description":"Base64 of the file, at most 1.5 MB of bytes (TRX’s inline limit). Never stored."}},"required":["kind","data"]},"description":"Each owner's ID (front required, back optional: id_front/id_back for the first owner, id2_front/id2_back for the second), a voided check or a bank letter, optionally a W-9 or an SS-4 (when the legal name does not match the EIN), and the signed application (`application`, required)"},"agreed":{"type":"boolean","const":true,"description":"The owner certifies the information and authorizes PlaceFull to share it with TRX"},"signature":{"type":"object","properties":{"name":{"type":"string","description":"The printed name the signer gave, ≤60 characters"},"method":{"type":"string","enum":["drawn","typed"],"description":"Drawn on the device, or the typed name"},"consent":{"type":"boolean","const":true,"description":"“I agree to sign electronically and that my electronic signature is my legal signature.”"}},"required":["name","method","consent"],"description":"The signer of the application. The record the server appends adds its own clock and the client IP and user agent"}},"required":["business","owners","bank","volumes","documents","agreed","signature"],"example":{"business":{"legalName":"Example Studio LLC","dba":"Example Studio","ein":"000000000","ownershipType":"LLC","established":"2021-03","phone":"555-555-0100","email":"owner@example.com","website":"https://example.com","address":"1 Example St","address2":"","city":"Portland","region":"OR","postal":"97201","merchandise":"Classes and events"},"owners":[{"firstName":"Avery","lastName":"Example","ownershipPercent":"100","email":"avery@example.com","phone":"555-555-0101","ssn":"111-11-1111","dateOfBirth":"1985-04-12","address":"2 Example Ave","city":"Portland","region":"OR","postal":"97202","licenseNumber":"EX1234567","licenseRegion":"OR","licenseExpiration":"2030-04-12"}],"bank":{"accountType":"checking","holder":"business","routing":"026013673","account":"11111111","feesSameAccount":true},"volumes":{"monthlyVolume":"12000","dailyVolume":"1500","averageTicket":"25","maximumTicket":"400"},"documents":[{"kind":"id_front","data":"/9j/4AAQSkZJRg=="},{"kind":"voided_check","data":"/9j/4AAQSkZJRg=="},{"kind":"application","data":"JVBERi0xLjcK"}],"agreed":true,"signature":{"name":"Avery Example","method":"drawn","consent":true}}},"TrxApplicationDocumentsBody":{"type":"object","properties":{"documents":{"minItems":1,"maxItems":5,"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["id_front","id_back","id2_front","id2_back","voided_check","bank_letter","w9","ss4","application"],"description":"`application` is TRX’s merchant application, filled and signed in the browser and drawn as page images (a 5-page PDF); the server appends the electronic signature record page"},"fileName":{"description":"Ignored: TRX files it as id-owner1-front.jpg and the like","type":"string"},"contentType":{"description":"Ignored: the bytes say what they are — JPEG, PNG or PDF","type":"string"},"data":{"type":"string","maxLength":2097152,"description":"Base64 of the file, at most 1.5 MB of bytes (TRX’s inline limit). Never stored."}},"required":["kind","data"]},"description":"A signed application is taken again only as the very pages that were signed (their SHA-256), with the first submit’s record"}},"required":["documents"],"example":{"documents":[{"kind":"voided_check","data":"/9j/4AAQSkZJRg=="}]}},"PutTrxPricingBody":{"type":"object","properties":{"model":{"type":"string","enum":["flat","interchange_plus"],"description":"flat: one discount rate and per-item fee; interchange_plus: interchange plus a markup"},"rateBps":{"type":"integer","minimum":0,"maximum":1000,"description":"Flat: the discount rate; interchange plus: the markup. Basis points (290 = 2.90%)"},"perItemCents":{"type":"integer","minimum":0,"maximum":10000,"description":"Per-item fee, cents"},"amexRateBps":{"description":"Interchange plus only: Amex’s markup; null = the same","anyOf":[{"type":"integer","minimum":0,"maximum":1000},{"type":"null"}]},"amexPerItemCents":{"description":"Interchange plus only: Amex’s per-item fee; null = the same","anyOf":[{"type":"integer","minimum":0,"maximum":10000},{"type":"null"}]},"batchFeeCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":10000},{"type":"null"}]},"chargebackFeeCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":10000},{"type":"null"}]}},"required":["model","rateBps","perItemCents"],"example":{"model":"flat","rateBps":290,"perItemCents":30,"batchFeeCents":null,"chargebackFeeCents":null}},"PutTrxAccountBody":{"type":"object","properties":{"merchantNumber":{"description":"The processor merchant id (MID)","anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"type":"string","minLength":1,"description":"The TRX client id"},"dba":{"anyOf":[{"type":"string"},{"type":"null"}]},"jsonUsername":{"type":"string","minLength":1,"description":"The gateway JSON login"},"jsonPassword":{"description":"Write-only. Required the first time; omit on a later write to keep the stored one. Never returned.","type":"string"},"storageSafeGuid":{"description":"The StorageSafe vault id","anyOf":[{"type":"string"},{"type":"null"}]},"country":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2 — the currency code comes from it"},"sharedWithLegacy":{"description":"Whether the legacy system still charges this merchant account. Omit to keep what is stored (false on a first write).","type":"boolean"}},"required":["clientId","jsonUsername","country"],"example":{"merchantNumber":"8788290000412","clientId":"412","dba":"Ash Street Yoga","jsonUsername":"000412_000002","jsonPassword":"example-only","storageSafeGuid":"A1B2C3D4E5F60718293A4B5C6D7E7A01","country":"US"}},"LegacyTrxPullBody":{"type":"object","properties":{"legacyAccountRef":{"type":"string","minLength":1,"maxLength":200,"description":"The studio's legacy PlaceFull account — its id, or the name in its PlaceFull links"}},"required":["legacyAccountRef"],"example":{"legacyAccountRef":"ash-street-yoga"}},"CreatePaymentBody":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","manual","trx"]},"purpose":{"type":"string","enum":["booking_deposit","booking_balance","booking_full","membership","open","cart"]},"amount":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"type":"string","minLength":3,"maxLength":3},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"membershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["provider","purpose","amount"],"example":{"provider":"stripe","purpose":"booking_deposit","amount":1500,"bookingId":"550e8400-e29b-41d4-a716-446655440005"}},"MoneyAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Amount in minor currency units (e.g. cents)","example":2500},"RefundPaymentBody":{"type":"object","properties":{"amount":{"$ref":"#/components/schemas/MoneyAmount"},"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["amount","expectedEffect"],"example":{"amount":1500,"expectedEffect":{"currency":"USD","movements":[{"direction":"refund","instrument":"card","amount":1500}]}}},"CreateCustomerBody":{"type":"object","properties":{"email":{"$ref":"#/components/schemas/Email"},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]},"givenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"familyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalGivenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalFamilyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"string","enum":["booking","import","manual"]},"tags":{"type":"array","items":{"type":"string"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"marketingConsent":{"type":"boolean"},"guardianCustomerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"example":{"email":"alex@example.com","displayName":"Alex Rivera","marketingConsent":true}},"ImportCustomersBody":{"type":"object","properties":{"rows":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"phone":{"type":"string"},"givenName":{"type":"string"},"familyName":{"type":"string"},"name":{"description":"A full name, split into first and last.","type":"string"},"tags":{"description":"Separated by commas, semicolons, or bars.","type":"string"},"notes":{"type":"string"},"consent":{"description":"Marketing emails: yes/no, true/false, 1/0, subscribed…","type":"string"},"customerSince":{"description":"A date: 2019-12-04 or 12/4/2019.","type":"string"}}}}},"required":["rows"],"example":{"rows":[{"email":"ana@example.com","givenName":"Ana","familyName":"Ruiz","consent":"Yes","customerSince":"2019-12-04"},{"phone":"303-555-0100","name":"Sam Lee"}]}},"UpdateCustomerBody":{"type":"object","properties":{"email":{"anyOf":[{"$ref":"#/components/schemas/Email"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]},"givenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"familyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"marketingConsent":{"type":"boolean"},"guardianCustomerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"example":{"tags":["vip"],"marketingConsent":true}},"MergeCustomerBody":{"type":"object","properties":{"fromCustomerId":{"$ref":"#/components/schemas/Uuid"},"keep":{"type":"object","properties":{"email":{"type":"string","enum":["into","from"]},"phone":{"type":"string","enum":["into","from"]},"name":{"type":"string","enum":["into","from"]}}}},"required":["fromCustomerId"],"example":{"fromCustomerId":"550e8400-e29b-41d4-a716-446655440006"}},"SplitCustomerBody":{"type":"object","properties":{"field":{"type":"string","enum":["email","phone"]}},"required":["field"],"example":{"field":"phone"}},"CreateMembershipPlanBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"type":"string","minLength":3,"maxLength":3},"billingPeriod":{"type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"expiresAfterDays":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]},"newCustomersOnly":{"type":"boolean"},"upsellAtCheckout":{"description":"Offer at checkout (passes): the checkout upsell under a class line considers only passes with this on. Omitted means true. The listing page's per-class hook ignores it.","type":"boolean"},"taxable":{"description":"Sales tax applies at the rates in Settings. Omitted means true (MDH-161).","type":"boolean"},"revenueCategoryId":{"description":"A revenue category of this business — its id, or its name. Null clears it. With one, `taxable` is inert (architecture/31).","anyOf":[{"type":"string"},{"type":"null"}]},"benefits":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["access","price","credit"]},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"example":{"mode":"percent","value":10,"scope":"all"}}},"required":["type","config"]}},"cardDesign":{"description":"The whole card design spec (architecture/27-cards.md § Spec). Strict: an unknown key or an out-of-set value is a 400 with a field path (`cardDesign.palette.ground`). `hand_set` and `designed_by` are written by the server — every field that differs from the stored spec (or, for a plan with none, the default design) is marked hand-set and `designed_by` becomes `owner`; an unchanged spec marks nothing. A create without it gets the default design, and the AI designs over it in the background.","type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","pattern","photo","logo","rationale"],"additionalProperties":false},"cardDesignProposal":{"description":"The `proposalToken` a card redesign returned. When `cardDesign` equals the proposed spec, the proposal is saved as proposed: `designed_by` stays the proposal's (`ai`), and `hand_set` keeps the stored fields plus the ones the redesign was asked to keep. A token that is expired, altered, or for another business, plan or spec is ignored, and the write is diffed as the owner's.","type":"string"}},"required":["name","priceAmount","billingPeriod"],"example":{"name":"Unlimited Monthly","priceAmount":9900,"billingPeriod":"monthly"}},"UpdateMembershipPlanBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"billingPeriod":{"type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"expiresAfterDays":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]},"newCustomersOnly":{"type":"boolean"},"upsellAtCheckout":{"description":"Offer at checkout (passes) — whether the checkout upsell may suggest this pass under a class.","type":"boolean"},"taxable":{"description":"Sales tax applies at the rates in Settings (MDH-161).","type":"boolean"},"revenueCategoryId":{"description":"A revenue category of this business — its id, or its name. Null clears it. With one, `taxable` is inert (architecture/31).","anyOf":[{"type":"string"},{"type":"null"}]},"benefits":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["access","price","credit"]},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"example":{"mode":"percent","value":10,"scope":"all"}}},"required":["type","config"]}},"cardDesign":{"description":"The whole card design spec (architecture/27-cards.md § Spec). Strict: an unknown key or an out-of-set value is a 400 with a field path (`cardDesign.palette.ground`). `hand_set` and `designed_by` are written by the server — every field that differs from the stored spec (or, for a plan with none, the default design) is marked hand-set and `designed_by` becomes `owner`; an unchanged spec marks nothing. A create without it gets the default design, and the AI designs over it in the background.","type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","pattern","photo","logo","rationale"],"additionalProperties":false},"cardDesignProposal":{"description":"The `proposalToken` a card redesign returned. When `cardDesign` equals the proposed spec, the proposal is saved as proposed: `designed_by` stays the proposal's (`ai`), and `hand_set` keeps the stored fields plus the ones the redesign was asked to keep. A token that is expired, altered, or for another business, plan or spec is ignored, and the write is diffed as the owner's.","type":"string"}},"example":{"name":"Unlimited Monthly","priceAmount":9900,"billingPeriod":"monthly"}},"PurchaseMembershipBody":{"type":"object","properties":{"planId":{"$ref":"#/components/schemas/Uuid"},"provider":{"type":"string","enum":["manual","card","link","stripe"],"description":"How the desk sells the plan (architecture/11 § Sell). `manual`: paid at the desk, cash or a paid-elsewhere method. `card`: charged now to the customer's card on file (a recurring plan then renews on it). `link`: a cart pay link for the customer to pay — the first period's charge saves the card (build-plan/265 D1). `stripe` is the old name for `link`."},"expectedEffect":{"description":"Required with `provider: manual` and `provider: card` — the desk sale moves money and grants credits, so echo the `membership.sell` declaration from `POST …/money-effects` (with the same `provider`). A pay link moves nothing at the desk and needs none.","$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["planId","provider"],"example":{"planId":"550e8400-e29b-41d4-a716-446655440010","provider":"link"}},"RecordMembershipPeriodPaymentBody":{"type":"object","properties":{"channelId":{"description":"The paid-elsewhere payment method the period was paid through (architecture/24 § Closing out). Without it the period would be cash, which is not taken: 403 `cash_not_taken`.","$ref":"#/components/schemas/Uuid"},"reference":{"description":"The other system's reference, as the method's rule asks (required, optional, or dropped).","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"amount":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/CurrencyCode"},"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"example":{"channelId":"00000000-0000-4000-8000-0000000000c1","reference":"POS-1042"}},"CancelMembershipBody":{"type":"object","properties":{"atPeriodEnd":{"description":"Cancel at period end (default true). Set false to cancel immediately.","type":"boolean"}},"example":{"atPeriodEnd":true}},"RetryMembershipRenewalBody":{"type":"object","properties":{"expectedEffect":{"description":"The `membership.renew` declaration from `POST …/money-effects` — the period's price to the card on file.","$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["expectedEffect"],"example":{"expectedEffect":{"currency":"USD","movements":[{"direction":"charge","instrument":"card","amount":9000}]}}},"QuoteListingBody":{"anyOf":[{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"description":"Who it is for — their memberships and credits price it. Omit to quote the listing for nobody yet: its price, tax and fee.","$ref":"#/components/schemas/Uuid"},"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"redeemCredits":{"type":"boolean"}},"required":["offeringId","partySize"]},{"type":"object","properties":{"variantId":{"$ref":"#/components/schemas/Uuid"},"quantity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"locationId":{"$ref":"#/components/schemas/Uuid"}},"required":["variantId","quantity","locationId"]}],"example":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","customerId":"550e8400-e29b-41d4-a716-446655440006","partySize":1}},"DiscountDraft":{"type":"object","properties":{"name":{"type":"string"},"code":{"anyOf":[{"type":"string"},{"type":"null"}]},"appliesTo":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","const":"all"}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","const":"category"},"category":{"type":"string","enum":["class","session","space","product"]}},"required":["kind","category"]},{"type":"object","properties":{"kind":{"type":"string","const":"listing"},"listingId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","listingId"]},{"type":"object","properties":{"kind":{"type":"string","const":"product"},"productId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","productId"]}]}},"effect":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","const":"percent"},"value":{"type":"integer","minimum":1,"maximum":100}},"required":["mode","value"]},{"type":"object","properties":{"mode":{"type":"string","const":"amount"},"value":{"type":"integer","minimum":1,"maximum":9007199254740991},"per":{"type":"string","enum":["unit","order"]}},"required":["mode","value","per"]},{"type":"object","properties":{"mode":{"type":"string","const":"price"},"value":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["mode","value"]}]},"every":{"type":"integer","minimum":1,"maximum":9007199254740991},"gets":{"type":"integer","minimum":1,"maximum":9007199254740991},"afterFirst":{"description":"Which spots get it, as a threshold: the first N spots in the cart pay full price and every spot after that gets the effect — a family's third child at half price. Counted across every line the discount applies to, taken on the cheapest spots. 0 (default) = every spot. Refused together with every > 1 or an amount off the order.","type":"integer","minimum":0,"maximum":9007199254740991},"when":{"anyOf":[{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},"start":{"anyOf":[{"type":"string"},{"type":"null"}]},"end":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["days","start","end"]},{"type":"null"}]},"minQuantity":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"minAmount":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"startsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"endsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"maxUses":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"status":{"type":"string","enum":["active","paused"]},"promote":{"description":"Listed on the listing's description under the price (default true). false = still applies on its own to every cart it fits, but is not listed. Only an automatic discount is listed, so this has no effect on a coded one.","type":"boolean"}},"required":["name","appliesTo","effect"],"example":{"name":"Wednesday: 10% off","appliesTo":[{"kind":"all"}],"effect":{"mode":"percent","value":10},"when":{"days":[3],"start":null,"end":null}}},"ChatUiContext":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120},"kind":{"type":"string","enum":["booking","offering","customer","page","money"]},"entity_id":{"type":"string"},"reference":{"type":"string","maxLength":40}},"required":["label"]},"InlineTranscriptTurn":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant"]},"text":{"type":"string"}},"required":["role","text"]},"InlineScheduleDraft":{"type":"object","properties":{"freq":{"type":"string","enum":["daily","weekly","monthly","dates"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"byWeekday":{"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"dates":{"type":"array","items":{"type":"string"}},"startTime":{"type":"string"},"startDate":{"type":"string"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sessionLengthMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"until":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["freq","interval","byWeekday","dates","startTime","startDate","durationMinutes","sessionLengthMinutes","until"]},"RequestChallengeBody":{"type":"object","properties":{"email":{"$ref":"#/components/schemas/Email"},"channel":{"description":"Defaults to email_code","$ref":"#/components/schemas/VerificationChannel"},"surface":{"description":"Which surface requested sign-in — baked into magic-link redirect when channel is email_link","type":"string","enum":["console","customer"]},"redirectTo":{"description":"Same-origin root-relative path only (e.g. /account): letters, digits and `/_-.?=&%~+`. Ignored otherwise.","type":"string"},"invite":{"description":"Pilot invite code. While sign-up is invite-only, a code goes to an email with no account only when this matches; otherwise the answer is the usual 201 and no email is sent. Ignored for existing accounts and when sign-up is open.","type":"string"}},"required":["email"],"example":{"email":"alex@example.com","channel":"email_code"}},"VerificationChannel":{"type":"string","enum":["email_link","email_code","sms_code"],"example":"email_code"},"VerifyChallengeBody":{"type":"object","properties":{"challengeId":{"$ref":"#/components/schemas/Uuid"},"code":{"type":"string","description":"Verification code from email/SMS","example":"123456"}},"required":["challengeId","code"],"example":{"challengeId":"550e8400-e29b-41d4-a716-446655440017","code":"123456"}},"UpdatePersonBody":{"type":"object","properties":{"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalGivenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalFamilyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"example":{"displayName":"Alex R."}},"CreateLocationBody":{"type":"object","properties":{"name":{"type":"string","example":"Downtown Studio"},"address":{"type":"string","example":"123 Main St, Denver, CO"},"timezone":{"type":"string","example":"America/Denver","description":"IANA timezone identifier"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactEmail":{"anyOf":[{"$ref":"#/components/schemas/Email"},{"type":"null"}]},"defaultConfirmationMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultClassDurationMinutes":{"description":"How long a new class runs, in minutes.","example":60,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"defaultAppointmentDurationMinutes":{"description":"How long a new reservation runs, in minutes.","example":60,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["name","address","timezone"],"example":{"name":"Downtown Studio","address":"123 Main St, Denver, CO","timezone":"America/Denver","country":"US","region":"CO","city":"Denver","postalCode":"80202"}},"UpdateLocationBody":{"type":"object","properties":{"name":{"type":"string","example":"Downtown Studio"},"address":{"type":"string","example":"123 Main St, Denver, CO"},"timezone":{"type":"string","example":"America/Denver","description":"IANA timezone identifier"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactEmail":{"anyOf":[{"$ref":"#/components/schemas/Email"},{"type":"null"}]},"defaultConfirmationMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultClassDurationMinutes":{"description":"How long a new class runs, in minutes.","example":60,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"defaultAppointmentDurationMinutes":{"description":"How long a new reservation runs, in minutes.","example":60,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hoursScheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"storefrontTheme":{"$ref":"#/components/schemas/StorefrontTheme"},"links":{"description":"Replaces every link. Closed keys; a URL, a bare host, or an @handle on Instagram, Facebook, TikTok, YouTube and X. Stored as https URLs.","type":"object","properties":{"website":{"anyOf":[{"type":"string"},{"type":"null"}]},"instagram":{"anyOf":[{"type":"string"},{"type":"null"}]},"facebook":{"anyOf":[{"type":"string"},{"type":"null"}]},"tiktok":{"anyOf":[{"type":"string"},{"type":"null"}]},"youtube":{"anyOf":[{"type":"string"},{"type":"null"}]},"x":{"anyOf":[{"type":"string"},{"type":"null"}]},"linkedin":{"anyOf":[{"type":"string"},{"type":"null"}]},"yelp":{"anyOf":[{"type":"string"},{"type":"null"}]},"google":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"bookingPaused":{"type":"boolean"},"messages":{"$ref":"#/components/schemas/LocationMessagesPatch"},"walkInsPublic":{"type":"boolean"},"embedCss":{"description":"The whole stylesheet for this location's plain embed tags, stored as written. Null or blank clears it. Every rule must start with one of the six tags; a sheet that does not, or one over 32 KB, is a 400 whose details carry `field: 'embedCss'` and the `issues`, each with its line.","anyOf":[{"type":"string"},{"type":"null"}]},"showAddress":{"description":"False hides the address and the map from customers. The stored address stays","type":"boolean"},"showPhone":{"type":"boolean"},"showEmail":{"type":"boolean"}},"example":{"name":"Downtown Studio — Updated"}},"StorefrontTheme":{"type":"object","properties":{"accent":{"description":"Customer-facing CTA color for this location’s pages and emails","anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"paper":{"description":"Page background hex. Ink and supporting tokens are derived so body text meets AA.","anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"ground":{"type":"string","enum":["paper","cream","stone","sage","ink"]},"type":{"type":"string","enum":["sans","serif","soft","editorial"]},"buttons":{"type":"string","enum":["pill","rounded","square","outline"]},"corners":{"type":"string","enum":["sharp","soft","round"]},"surface":{"type":"string","enum":["flat","raised","lined"]},"hero":{"type":"string","enum":["split","bleed","type"]},"header":{"type":"string","enum":["plain","bar","overlay"]},"display":{"type":"string","enum":["quiet","standard","bold"]}},"example":{}},"LocationMessagesPatch":{"type":"object","properties":{"pausedReason":{"anyOf":[{"type":"string","maxLength":160,"description":"Added after the notice that bookings are paused."},{"type":"null"}]},"scheduleEmpty":{"anyOf":[{"type":"string","maxLength":120,"description":"Shown where the times would be."},{"type":"null"}]},"soldOut":{"anyOf":[{"type":"string","maxLength":200,"description":"Shown above the waitlist when the time they picked is full."},{"type":"null"}]},"passwordPrompt":{"anyOf":[{"type":"string","maxLength":160,"description":"The line above the password field on a listing with a password."},{"type":"null"}]},"bookedHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"enrolledHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"waitlistJoinedNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added after their place in line."},{"type":"null"}]},"waitlistOfferHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"waitlistOfferNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the offer. The deadline stays."},{"type":"null"}]},"waitlistMissedHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"waitlistMissedNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under our sentence."},{"type":"null"}]},"movedHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"movedNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the new time."},{"type":"null"}]},"canceledByStudioHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"canceledByStudioNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},{"type":"null"}]},"canceledByCustomerHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"canceledByCustomerNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},{"type":"null"}]},"enrollmentCanceledHeadline":{"anyOf":[{"type":"string","maxLength":60,"description":"The headline of the email."},{"type":"null"}]},"enrollmentCanceledNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},{"type":"null"}]},"refundNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the amount, which stays."},{"type":"null"}]},"balanceNote":{"anyOf":[{"type":"string","maxLength":300,"description":"Added under the amount, which stays."},{"type":"null"}]}},"example":{"pausedReason":"Closed for the holidays, back Jan 5."}},"StrandedDecision":{"type":"string","enum":["keep","cancel"],"description":"Booked dates this change would leave off the schedule: `keep` — they still run as they are and stay on the calendar flagged; `cancel` — each is cancelled through the studio cancel (refund regardless of the customer’s window, cancellation email, series rule kept). Omit to be told which dates first: the write answers `409` with `{ code: \"stranded_dates\", dates }` and writes nothing.","example":"keep"},"CreateResourceBody":{"type":"object","properties":{"kind":{"type":"string","enum":["room","equipment"]},"name":{"type":"string"},"capacity":{"description":"Spots mode. Omitted when tables is sent — capacity is the sum of those spots.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"hoursByDay":{"description":"Replaces the days whose hours differ from the location's; null follows the location every day (build-plan/196).","anyOf":[{"type":"object","properties":{"mon":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"tue":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"wed":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"thu":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"fri":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"sat":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"sun":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]}}},{"type":"null"}]},"positionLayout":{"type":"string","enum":["list","grid"]},"seating":{"description":"How the tables seat parties: booked (each booking takes a table) or door (the host seats them; the default).","type":"string","enum":["booked","door"]},"positions":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"tables":{"description":"Table mode. Capacity becomes the sum of spots. An empty list returns to spots mode. A table without x/y/width/height is sized by shape, spots and rotation and placed in the first open spot of the 1000 × 600 room. Rotation is a clockwise quarter turn; omitted, 0.","type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"spots":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"shape":{"type":"string","enum":["round","square","rect","booth"]},"share":{"type":"boolean"},"x":{"type":"integer","minimum":0,"maximum":9007199254740991},"y":{"type":"integer","minimum":0,"maximum":9007199254740991},"width":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"height":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"rotation":{"anyOf":[{"type":"number","const":0},{"type":"number","const":90},{"type":"number","const":180},{"type":"number","const":270}]}},"required":["spots"]}}},"required":["kind","name"],"example":{"kind":"room","name":"Studio A","capacity":20}},"UpdateResourceBody":{"type":"object","properties":{"kind":{"type":"string","enum":["room","equipment"]},"name":{"type":"string"},"capacity":{"description":"Spots mode. Omitted when tables is sent — capacity is the sum of those spots.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"hoursByDay":{"description":"Replaces the days whose hours differ from the location's; null follows the location every day (build-plan/196).","anyOf":[{"type":"object","properties":{"mon":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"tue":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"wed":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"thu":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"fri":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"sat":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]},"sun":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"]},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"]}]}}},{"type":"null"}]},"positionLayout":{"type":"string","enum":["list","grid"]},"seating":{"description":"How the tables seat parties: booked (each booking takes a table) or door (the host seats them; the default).","type":"string","enum":["booked","door"]},"positions":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"tables":{"description":"Table mode. Capacity becomes the sum of spots. An empty list returns to spots mode. A table without x/y/width/height is sized by shape, spots and rotation and placed in the first open spot of the 1000 × 600 room. Rotation is a clockwise quarter turn; omitted, 0.","type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"spots":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"shape":{"type":"string","enum":["round","square","rect","booth"]},"share":{"type":"boolean"},"x":{"type":"integer","minimum":0,"maximum":9007199254740991},"y":{"type":"integer","minimum":0,"maximum":9007199254740991},"width":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"height":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"rotation":{"anyOf":[{"type":"number","const":0},{"type":"number","const":90},{"type":"number","const":180},{"type":"number","const":270}]}},"required":["spots"]}}},"example":{"capacity":24}},"CreateInstructorProfileBody":{"type":"object","properties":{"personId":{"$ref":"#/components/schemas/Uuid"},"email":{"$ref":"#/components/schemas/Email"},"name":{"type":"string"},"bio":{"type":"string"},"headshotUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"specialties":{"type":"array","items":{"type":"string"}},"public":{"type":"boolean"},"notifyBookings":{"description":"Email or text when someone books, cancels, or moves a time they teach. Default true.","type":"boolean"},"instagram":{"description":"Instagram handle. A leading @ is stripped. Empty clears it.","anyOf":[{"type":"string"},{"type":"null"}]},"locationIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"hours":{"description":"Own bookable windows per site. Each entry replaces that location's rows; sites left out are untouched. Empty scheduleIds = follow the location's hours.","type":"array","items":{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"},"scheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["locationId","scheduleIds"]}}},"example":{"email":"instructor@example.com","name":"Alex Rivera","bio":"RYT-200 instructor"}},"UpdateInstructorProfileBody":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"bio":{"type":"string"},"headshotUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"specialties":{"type":"array","items":{"type":"string"}},"public":{"type":"boolean"},"notifyBookings":{"description":"Email or text when someone books, cancels, or moves a time they teach. Default true.","type":"boolean"},"instagram":{"description":"Instagram handle. A leading @ is stripped. Empty clears it.","anyOf":[{"type":"string"},{"type":"null"}]},"locationIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"hours":{"description":"Own bookable windows per site. Each entry replaces that location's rows; sites left out are untouched. Empty scheduleIds = follow the location's hours.","type":"array","items":{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"},"scheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["locationId","scheduleIds"]}}},"example":{"bio":"E-RYT 500 instructor"}},"CreateListingBody":{"type":"object","properties":{"type":{"type":"string","enum":["class","session","space"]},"exclusive":{"type":"boolean"},"customerWord":{"description":"The group this listing sits in — a preset (class, event, …) or a name this studio typed, offered again on the next listing. Null follows the business word for its kind.","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"name":{"type":"string"},"slug":{"type":"string"},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"type":"string","minLength":3,"maxLength":3},"taxable":{"description":"Sales tax applies at the rates in Settings. Default true; inert until the business holds rates.","type":"boolean"},"priceParts":{"description":"Split the price across revenue categories — the whole set, replace-all; [] clears it. Amounts per unit, above zero, never summing above priceAmount; the rest follows revenueCategoryId (architecture/31).","type":"array","items":{"type":"object","properties":{"amount":{"$ref":"#/components/schemas/MoneyAmount"},"revenueCategoryId":{"type":"string","description":"A revenue category of this business — its id, or its name."}},"required":["amount","revenueCategoryId"]}},"priceTiers":{"description":"Named prices beside the base — the whole list, in order; a tier left out is removed (booked lines keep it); [] clears them (architecture/03 § Price tiers).","type":"array","items":{"type":"object","properties":{"id":{"description":"A tier this listing has — kept and edited. Omit for a new one.","type":"string"},"label":{"type":"string"},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"unit":{"type":"string","enum":["booking","spot"]},"minQty":{"description":"Default 1.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxQty":{"description":"Default minQty. Never above capacity.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"extraAmount":{"description":"A package only: the amount per spot past maxQty, which then sells to the spots left; null or absent stops at maxQty (build-plan/290).","anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]}},"required":["label","priceAmount","unit"]}},"revenueCategoryId":{"description":"A revenue category of this business — its id, or its name. Null clears it. With one, `taxable` is inert (architecture/31).","anyOf":[{"type":"string"},{"type":"null"}]},"depositType":{"type":"string","enum":["none","fixed","percent"]},"depositAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"capacity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"minPartySize":{"description":"Spots per booking: the fewest one online booking takes. Null = no limit. Staff bookings are not held to it; moot on a buyout.","anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"maxPartySize":{"description":"Spots per booking: the most one online booking takes; never below `minPartySize`. Null = no limit.","anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"largerPartyOfferingId":{"description":"The listing a larger group is pitched on the public page (\"Bringing 8 or more?\" → See the Party room): above `maxPartySize` per spot, or above the top of the group prices by group. A listing of this business, never itself.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditCost":{"description":"Credits to cover one spot (default 1; 0 is free without consuming credits).","type":"integer","minimum":0,"maximum":9007199254740991},"durationMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"slotGranularityMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bookingHorizonDays":{"description":"Days ahead people can book; null follows the business default.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bookingCutoffMinutes":{"description":"Minutes before start when booking closes; null follows the business default.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"cancellationCutoffHours":{"description":"Hours before start when cancelling closes; null follows the business default, 0 is any time, -1 is no cancellation.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"rescheduleCutoffHours":{"description":"Hours before start when changing the time closes; null follows the business default, 0 is until the start, -1 is no changes.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"spotsLeft":{"description":"Spots left on its storefront times: few or always; null follows the business setting (build-plan/238).","anyOf":[{"type":"string","enum":["few","always"]},{"type":"null"}]},"priceName":{"description":"The first price's name — what customers pick (\"Spot\", \"Birthday party\"); null or blank reads \"Spot\" (build-plan/215).","anyOf":[{"type":"string"},{"type":"null"}]},"priceUnit":{"description":"The first price is per person (spot) or for the group (booking — once for a headcount between minPartySize and maxPartySize). A buyout is always booking.","type":"string","enum":["spot","booking"]},"priceExtraAmount":{"description":"A group first price only: the amount per spot past maxPartySize, which then sells to capacity; null is none (build-plan/290).","anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"pricing":{"description":"standard (default) pays when they book; subscription (build-plan/280) holds their spots in every session it covers and bills per spot every billingTerm. Per spot, one price, no deposit; never a rental.","type":"string","enum":["standard","subscription"]},"billingTerm":{"description":"Required with pricing subscription.","anyOf":[{"type":"string","enum":["weekly","monthly"]},{"type":"null"}]},"subscribeTo":{"description":"A class subscription covers every session (default) or one weekly time the customer picks; an appointment is always one time a week.","anyOf":[{"type":"string","enum":["every_session","one_time_a_week"]},{"type":"null"}]},"resourceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"tableIds":{"description":"The tables it seats at in its room — table ids, or table names in that room; [] is every table. Replace-all. A new room or a buyout drops them (build-plan/214).","type":"array","items":{"type":"string"}},"instructorIds":{"description":"Who teaches it, or who can take a reservation — in assignment order. Instructor profile ids; a team member's person id works too, and gives them a hidden instructor profile in the same write.","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"requiredAccessKeys":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"password":{"description":"Customers enter it on the listing's page to see and book it — a convenience, not security, kept as written. Null or blank clears it, which also puts the listing back on the page.","anyOf":[{"type":"string","maxLength":64},{"type":"null"}]},"showOnPage":{"description":"false keeps a password listing off every list on the studio's pages; its link still opens it. Refused without a password.","type":"boolean"},"confirmationMessage":{"description":"Override location default confirmation copy; null inherits.","anyOf":[{"type":"string"},{"type":"null"}]},"meetingUrl":{"description":"https link included on the confirmation and the day-of reminder. A bare host is stored as https. Null clears it.","anyOf":[{"type":"string"},{"type":"null"}]},"meetingInstructions":{"description":"Short note sent with the meeting link. Null clears it. 500 characters.","anyOf":[{"type":"string"},{"type":"null"}]},"place":{"description":"Where it is held. on_site (default) keeps its space. off_site needs placeName or placeAddress and leaves its space. online needs meetingUrl and leaves its space. A space rental is always on_site.","type":"string","enum":["on_site","off_site","online"]},"placeName":{"description":"Off site: the place's name, e.g. Riverside Park. Cleared on any other place.","anyOf":[{"type":"string"},{"type":"null"}]},"placeAddress":{"description":"Off site: the place's address. Cleared on any other place.","anyOf":[{"type":"string"},{"type":"null"}]},"placeLat":{"description":"Off site: the address's pin, when known.","anyOf":[{"type":"number"},{"type":"null"}]},"placeLng":{"anyOf":[{"type":"number"},{"type":"null"}]},"placeNote":{"description":"Off site: where in the place to go (500 characters). Public. Cleared on any other place.","anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"level":{"description":"Short level label — e.g. Beginner, All levels (build-plan/72).","anyOf":[{"type":"string"},{"type":"null"}]},"whatToBring":{"description":"What to bring — plain text or short markdown (build-plan/72).","anyOf":[{"type":"string"},{"type":"null"}]},"color":{"description":"The color it wears in the console: a #rrggbb, a swatch name (red, clay, blue, …), or a category name already stored. Omitted on create, a name is assigned from the id.","type":"string"},"icon":{"description":"The icon it wears in the console, in that color. A picker key, or its label. Null wears the kind's own glyph.","anyOf":[{"type":"string","enum":["artboard","glass-full","wheel","hands","mug","brush","glass","flame","pencil","cookie","palette","door","moon","heart","users","kid","senior","tent","series","tools","cake","lock","team","school","fundraiser","tree","pumpkin","leaf","hearts","egg","flower","tie","star","confetti","skull","sun","ticket","gift-card","building","cash","beach","graduation-cap","dumbbell","kettlebell","biceps","person-standing","heart-pulse","timer","zap","bike","footprints","waves","user","baby","paintbrush","amphora","hand","scissors","sparkles","music","mic","camera","utensils","coffee","book"]},{"type":"null"}]},"scheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"questionIds":{"description":"Ordered checkout questions from the business catalog — each booking answers its own (build-plan/239).","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"questionPrices":{"description":"Replace-all: the questions asked for some of the listing's prices only (build-plan/239 § 7) — each names a question it asks and one or more of its prices (a tier's id, null for the first price); a question not named asks every price. Naming every price is no restriction. A price or question this same write removes drops off; one that was never the listing's is a 400. Removing a price later takes it off; a question left with none asks every price.","type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"prices":{"minItems":1,"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}}},"required":["questionId","prices"]}},"agreementMode":{"description":"Deprecated (build-plan/222): none asks nothing; location sets the location's every-listing documents; own reads agreementDocumentIds.","type":"string","enum":["location","own","none"]},"agreementDocumentIds":{"description":"Waivers & terms (architecture/33): the location's documents customers agree to, in order. Replace-all. A new listing without it starts with the location's every-listing documents.","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"productIds":{"description":"Ordered add-ons. Replace-all like questionIds. `required` default false; `maxPerSpot` null means one (architecture/26).","type":"array","items":{"type":"object","properties":{"productId":{"$ref":"#/components/schemas/Uuid"},"required":{"type":"boolean"},"maxPerSpot":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]}},"required":["productId"]}},"dropInEnabled":{"description":"When false, the class sells series runs only (build-plan/154). Default true.","type":"boolean"},"personChoice":{"description":"Reservations: who picks the instructor when several can take it — `customer` (default; the storefront offers Anyone plus each public person) or `any` (the studio assigns in instructorIds order).","type":"string","enum":["customer","any"]}},"required":["type","name","slug","priceAmount","capacity"],"example":{"type":"class","name":"Morning Flow","slug":"morning-flow","priceAmount":3000,"capacity":20}},"UpdateListingBody":{"type":"object","properties":{"type":{"type":"string","enum":["class","session","space"]},"exclusive":{"type":"boolean"},"customerWord":{"description":"The group this listing sits in — a preset (class, event, …) or a name this studio typed, offered again on the next listing. Null follows the business word for its kind.","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"name":{"type":"string"},"slug":{"type":"string"},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"type":"string","minLength":3,"maxLength":3},"taxable":{"description":"Sales tax applies at the rates in Settings. Default true; inert until the business holds rates.","type":"boolean"},"priceParts":{"description":"Split the price across revenue categories — the whole set, replace-all; [] clears it. Amounts per unit, above zero, never summing above priceAmount; the rest follows revenueCategoryId (architecture/31).","type":"array","items":{"type":"object","properties":{"amount":{"$ref":"#/components/schemas/MoneyAmount"},"revenueCategoryId":{"type":"string","description":"A revenue category of this business — its id, or its name."}},"required":["amount","revenueCategoryId"]}},"priceTiers":{"description":"Named prices beside the base — the whole list, in order; a tier left out is removed (booked lines keep it); [] clears them (architecture/03 § Price tiers).","type":"array","items":{"type":"object","properties":{"id":{"description":"A tier this listing has — kept and edited. Omit for a new one.","type":"string"},"label":{"type":"string"},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"unit":{"type":"string","enum":["booking","spot"]},"minQty":{"description":"Default 1.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxQty":{"description":"Default minQty. Never above capacity.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"extraAmount":{"description":"A package only: the amount per spot past maxQty, which then sells to the spots left; null or absent stops at maxQty (build-plan/290).","anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]}},"required":["label","priceAmount","unit"]}},"revenueCategoryId":{"description":"A revenue category of this business — its id, or its name. Null clears it. With one, `taxable` is inert (architecture/31).","anyOf":[{"type":"string"},{"type":"null"}]},"depositType":{"type":"string","enum":["none","fixed","percent"]},"depositAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"capacity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"minPartySize":{"description":"Spots per booking: the fewest one online booking takes. Null = no limit. Staff bookings are not held to it; moot on a buyout.","anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"maxPartySize":{"description":"Spots per booking: the most one online booking takes; never below `minPartySize`. Null = no limit.","anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"largerPartyOfferingId":{"description":"The listing a larger group is pitched on the public page (\"Bringing 8 or more?\" → See the Party room): above `maxPartySize` per spot, or above the top of the group prices by group. A listing of this business, never itself.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditCost":{"description":"Credits to cover one spot (default 1; 0 is free without consuming credits).","type":"integer","minimum":0,"maximum":9007199254740991},"durationMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"slotGranularityMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bookingHorizonDays":{"description":"Days ahead people can book; null follows the business default.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bookingCutoffMinutes":{"description":"Minutes before start when booking closes; null follows the business default.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"cancellationCutoffHours":{"description":"Hours before start when cancelling closes; null follows the business default, 0 is any time, -1 is no cancellation.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"rescheduleCutoffHours":{"description":"Hours before start when changing the time closes; null follows the business default, 0 is until the start, -1 is no changes.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"spotsLeft":{"description":"Spots left on its storefront times: few or always; null follows the business setting (build-plan/238).","anyOf":[{"type":"string","enum":["few","always"]},{"type":"null"}]},"priceName":{"description":"The first price's name — what customers pick (\"Spot\", \"Birthday party\"); null or blank reads \"Spot\" (build-plan/215).","anyOf":[{"type":"string"},{"type":"null"}]},"priceUnit":{"description":"The first price is per person (spot) or for the group (booking — once for a headcount between minPartySize and maxPartySize). A buyout is always booking.","type":"string","enum":["spot","booking"]},"priceExtraAmount":{"description":"A group first price only: the amount per spot past maxPartySize, which then sells to capacity; null is none (build-plan/290).","anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"pricing":{"description":"standard (default) pays when they book; subscription (build-plan/280) holds their spots in every session it covers and bills per spot every billingTerm. Per spot, one price, no deposit; never a rental.","type":"string","enum":["standard","subscription"]},"billingTerm":{"description":"Required with pricing subscription.","anyOf":[{"type":"string","enum":["weekly","monthly"]},{"type":"null"}]},"subscribeTo":{"description":"A class subscription covers every session (default) or one weekly time the customer picks; an appointment is always one time a week.","anyOf":[{"type":"string","enum":["every_session","one_time_a_week"]},{"type":"null"}]},"resourceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"tableIds":{"description":"The tables it seats at in its room — table ids, or table names in that room; [] is every table. Replace-all. A new room or a buyout drops them (build-plan/214).","type":"array","items":{"type":"string"}},"instructorIds":{"description":"Who teaches it, or who can take a reservation — in assignment order. Instructor profile ids; a team member's person id works too, and gives them a hidden instructor profile in the same write.","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"requiredAccessKeys":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"password":{"description":"Customers enter it on the listing's page to see and book it — a convenience, not security, kept as written. Null or blank clears it, which also puts the listing back on the page.","anyOf":[{"type":"string","maxLength":64},{"type":"null"}]},"showOnPage":{"description":"false keeps a password listing off every list on the studio's pages; its link still opens it. Refused without a password.","type":"boolean"},"confirmationMessage":{"description":"Override location default confirmation copy; null inherits.","anyOf":[{"type":"string"},{"type":"null"}]},"meetingUrl":{"description":"https link included on the confirmation and the day-of reminder. A bare host is stored as https. Null clears it.","anyOf":[{"type":"string"},{"type":"null"}]},"meetingInstructions":{"description":"Short note sent with the meeting link. Null clears it. 500 characters.","anyOf":[{"type":"string"},{"type":"null"}]},"place":{"description":"Where it is held. on_site (default) keeps its space. off_site needs placeName or placeAddress and leaves its space. online needs meetingUrl and leaves its space. A space rental is always on_site.","type":"string","enum":["on_site","off_site","online"]},"placeName":{"description":"Off site: the place's name, e.g. Riverside Park. Cleared on any other place.","anyOf":[{"type":"string"},{"type":"null"}]},"placeAddress":{"description":"Off site: the place's address. Cleared on any other place.","anyOf":[{"type":"string"},{"type":"null"}]},"placeLat":{"description":"Off site: the address's pin, when known.","anyOf":[{"type":"number"},{"type":"null"}]},"placeLng":{"anyOf":[{"type":"number"},{"type":"null"}]},"placeNote":{"description":"Off site: where in the place to go (500 characters). Public. Cleared on any other place.","anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"level":{"description":"Short level label — e.g. Beginner, All levels (build-plan/72).","anyOf":[{"type":"string"},{"type":"null"}]},"whatToBring":{"description":"What to bring — plain text or short markdown (build-plan/72).","anyOf":[{"type":"string"},{"type":"null"}]},"color":{"description":"The color it wears in the console: a #rrggbb, a swatch name (red, clay, blue, …), or a category name already stored. Omitted on create, a name is assigned from the id.","type":"string"},"icon":{"description":"The icon it wears in the console, in that color. A picker key, or its label. Null wears the kind's own glyph.","anyOf":[{"type":"string","enum":["artboard","glass-full","wheel","hands","mug","brush","glass","flame","pencil","cookie","palette","door","moon","heart","users","kid","senior","tent","series","tools","cake","lock","team","school","fundraiser","tree","pumpkin","leaf","hearts","egg","flower","tie","star","confetti","skull","sun","ticket","gift-card","building","cash","beach","graduation-cap","dumbbell","kettlebell","biceps","person-standing","heart-pulse","timer","zap","bike","footprints","waves","user","baby","paintbrush","amphora","hand","scissors","sparkles","music","mic","camera","utensils","coffee","book"]},{"type":"null"}]},"scheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"questionIds":{"description":"Ordered checkout questions from the business catalog — each booking answers its own (build-plan/239).","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"questionPrices":{"description":"Replace-all: the questions asked for some of the listing's prices only (build-plan/239 § 7) — each names a question it asks and one or more of its prices (a tier's id, null for the first price); a question not named asks every price. Naming every price is no restriction. A price or question this same write removes drops off; one that was never the listing's is a 400. Removing a price later takes it off; a question left with none asks every price.","type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"prices":{"minItems":1,"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}}},"required":["questionId","prices"]}},"agreementMode":{"description":"Deprecated (build-plan/222): none asks nothing; location sets the location's every-listing documents; own reads agreementDocumentIds.","type":"string","enum":["location","own","none"]},"agreementDocumentIds":{"description":"Waivers & terms (architecture/33): the location's documents customers agree to, in order. Replace-all. A new listing without it starts with the location's every-listing documents.","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"productIds":{"description":"Ordered add-ons. Replace-all like questionIds. `required` default false; `maxPerSpot` null means one (architecture/26).","type":"array","items":{"type":"object","properties":{"productId":{"$ref":"#/components/schemas/Uuid"},"required":{"type":"boolean"},"maxPerSpot":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]}},"required":["productId"]}},"dropInEnabled":{"description":"When false, the class sells series runs only (build-plan/154). Default true.","type":"boolean"},"personChoice":{"description":"Reservations: who picks the instructor when several can take it — `customer` (default; the storefront offers Anyone plus each public person) or `any` (the studio assigns in instructorIds order).","type":"string","enum":["customer","any"]},"strandedDates":{"$ref":"#/components/schemas/StrandedDecision"}},"example":{"priceAmount":3500}},"CreateSeriesBody":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"startsOn":{"type":"string","description":"First candidate day (YYYY-MM-DD) in the schedule timezone."},"sessionCount":{"anyOf":[{"type":"integer","minimum":2,"maximum":9007199254740991},{"type":"null"}]},"endsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"type":"string","minLength":3,"maxLength":3},"creditCost":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"enrollmentClosesAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["startsOn","priceAmount","priceCurrency"],"example":{"name":"Intro to Pottery, Sep 15 – Oct 20","startsOn":"2026-09-15","sessionCount":6,"priceAmount":24000,"priceCurrency":"USD"}},"UpdateSeriesBody":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"startsOn":{"type":"string","description":"First candidate day (YYYY-MM-DD) in the schedule timezone."},"sessionCount":{"anyOf":[{"type":"integer","minimum":2,"maximum":9007199254740991},{"type":"null"}]},"endsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"type":"string","minLength":3,"maxLength":3},"creditCost":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"enrollmentClosesAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"example":{"priceAmount":22000,"name":"Intro to Pottery"}},"UpdateOccurrenceBody":{"type":"object","properties":{"instructorIds":{"description":"Who teaches this date. Replaces the assigned instructors; empty means nobody.","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"resourceId":{"description":"The space this date moves to; null puts it in no room.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"capacityOverride":{"description":"Spots for this date only; null clears the override.","anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]}},"example":{"instructorIds":["0192b4d1-2f2a-7a5e-9d3c-0d7a1c2b3e4f"]}},"CancelOccurrenceBody":{"type":"object","properties":{"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"},"message":{"description":"Optional: the studio's own words to everyone booked. Rides each cancellation email (and the text when it fits); appended to the one series notice. Blank is no note.","anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]}},"required":["expectedEffect"],"example":{"expectedEffect":{"currency":"USD","movements":[{"direction":"refund","instrument":"card","amount":5000}]},"message":"The studio flooded overnight — we are so sorry. Thursday runs as planned."}},"MaterializeOccurrenceBody":{"type":"object","properties":{"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"}},"required":["occurrenceId","offeringId"],"example":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","offeringId":"550e8400-e29b-41d4-a716-446655440004"}},"AddTeamMemberBody":{"type":"object","properties":{"email":{"$ref":"#/components/schemas/Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"roles":{"type":"array","items":{"type":"string"}},"featureOverrides":{"description":"Adjust on a new row (build-plan/256): keys granted beyond the roles’ bundle and keys revoked from it. Refused for someone already on the team — change theirs with PATCH /user-roles/{id}.","$ref":"#/components/schemas/FeatureOverrides"},"profile":{"anyOf":[{"type":"object","properties":{"bio":{"type":"string"},"specialties":{"type":"array","items":{"type":"string"}},"public":{"type":"boolean"},"notifyBookings":{"type":"boolean"}}},{"type":"null"}]}},"required":["email"],"example":{"email":"casey@mdholt.com","name":"Casey Morgan","roles":["manager"],"profile":{"bio":"Vinyasa and restorative.","specialties":["Vinyasa"],"public":true}}},"FeatureOverrides":{"type":"object","properties":{"grant":{"type":"array","items":{"type":"string"}},"revoke":{"type":"array","items":{"type":"string"}}},"required":["grant","revoke"],"example":{"grant":["booking.manage"],"revoke":[]}},"GrantUserRoleBody":{"type":"object","properties":{"personId":{"description":"Someone already on this team. Anyone else is named by `email`; pass one or the other.","$ref":"#/components/schemas/Uuid"},"email":{"$ref":"#/components/schemas/Email"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"roles":{"type":"array","items":{"type":"string"}},"featureOverrides":{"$ref":"#/components/schemas/FeatureOverrides"}},"required":["roles"],"example":{"personId":"550e8400-e29b-41d4-a716-446655440001","roles":["employee"]}},"SetBusinessFeaturesBody":{"type":"object","properties":{"features":{"type":"array","items":{"type":"string"}}},"required":["features"],"example":{"features":["booking.view","booking.manage"]}},"UpdateUserRoleBody":{"type":"object","properties":{"roles":{"type":"array","items":{"type":"string"}},"featureOverrides":{"$ref":"#/components/schemas/FeatureOverrides"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"example":{"roles":["manager"]}},"JoinWaitlistBody":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"$ref":"#/components/schemas/Uuid"},"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["offeringId","occurrenceId","customerId","partySize"],"example":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","customerId":"550e8400-e29b-41d4-a716-446655440006","partySize":1}},"UpdateMyCustomerBody":{"type":"object","properties":{"phone":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"smsConsent":{"type":"boolean"}},"required":["phone"],"example":{"phone":"+13035550123","smsConsent":true}},"StorefrontQuoteBody":{"type":"object","properties":{"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"redeemCredits":{"type":"boolean"}},"required":["partySize"],"example":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","partySize":1}},"StorefrontWaitlistJoinBody":{"type":"object","properties":{"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string"}},"required":["occurrenceId"],"example":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","partySize":1,"email":"maya@example.com","name":"Maya Rivera"}},"StorefrontSubscriptionWaitlistJoinBody":{"type":"object","properties":{"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"occurrenceId":{"type":"string"},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string"}},"example":{"partySize":2,"occurrenceId":"01a1294b-e81e-74e5-b171-eebf64c9bbba:2026-11-05T18:00:00.000Z","email":"june.park@example.com","name":"June Park"}},"StorefrontWaitlistLeaveBody":{"type":"object","properties":{"token":{"type":"string","description":"The `leaveToken` from the join, or from GET /me/subscriptions."}},"required":["token"],"example":{"token":"MDFhMTQ2MTY.k3J9xQ2mVZ4pL8wR7tYb1A"}},"CreateCartBody":{"type":"object","properties":{"businessId":{"$ref":"#/components/schemas/Uuid"},"item":{"$ref":"#/components/schemas/CartItemBody"},"analytics":{"description":"PostHog's distinct id (`visitor`) and session id (`session`) for this browser, so the database can find the visit in PostHog (architecture/25 § Analytics). Each is kept when it is 1 to 64 characters with no control character; anything else is dropped, never refused.","type":"object","properties":{"visitor":{"type":"string","maxLength":64},"session":{"type":"string","maxLength":64}}}},"example":{"item":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","partySize":1}}},"CartItemAnswersBody":{"type":"object","properties":{"answers":{"type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"]}]}},"required":["questionId","value"]}}},"required":["answers"],"example":{"answers":[{"questionId":"550e8400-e29b-41d4-a716-446655440077","value":"Leo, turning 5"}]}},"CardSessionBody":{"type":"object","properties":{"wallets":{"description":"`true`: a session for TRX's Apple Pay and Google Pay buttons as well, priced as the page's viewer sees the cart (a signed-in member, `?others=`). Honoured only where wallets are offered — `TRX_WALLETS_ENABLED` and the platform's own host, never a studio's custom domain; elsewhere the answer is a plain card session. The page asks only outside an embed.","type":"boolean"}},"example":{"wallets":true}},"CheckoutCartBody":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","manual","trx"]},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string","maxLength":120},"phone":{"type":"string","maxLength":40},"smsConsent":{"type":"boolean"},"answers":{"description":"By question id, for any line that holds no answer to it — what a page loaded before lines held their own answers sends (build-plan/239; kept one release). Validated under the cart lock; a missing required answer fails before anything is charged.","type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"]}]}},"required":["questionId","value"]}},"lineAnswers":{"description":"The lines checkout asked in place (build-plan/239 T5) — a pay link the desk built, a plain embed's line — each with its own answers, standing for what the line held. A failure is a 400 whose `details.items` names each line and its questions.","type":"array","items":{"type":"object","properties":{"itemId":{"$ref":"#/components/schemas/Uuid"},"answers":{"type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"]}]}},"required":["questionId","value"]}}},"required":["itemId","answers"]}},"attendees":{"type":"array","items":{"type":"object","properties":{"bookingId":{"$ref":"#/components/schemas/Uuid"},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string","maxLength":200}},"required":["bookingId"]}},"marketingEmailConsent":{"type":"boolean"},"agreementsAccepted":{"description":"The customer's tick for the studio's waivers & terms (the cart's `agreements`). Required when the cart asks for any the payer has not agreed to; a guest is always asked (architecture/33).","type":"boolean"},"card":{"description":"Required on a `trx` checkout that owes money (409 `card_required` without it); ignored on every other provider. The card is charged inside this request.","type":"object","properties":{"data":{"type":"string","maxLength":8192,"description":"`Encrypted.Data` from TRX's card fields (`getEncryptedCardData()`): the card encrypted in TRX's iframe. Good for 15 minutes; never stored or logged."},"keyId":{"type":"string","maxLength":128,"description":"`Encrypted.KeyId` — which TRX public key encrypted it."},"postal":{"description":"The cardholder's ZIP or postal code, from our own form.","type":"string","maxLength":16},"bin":{"description":"`Encrypted.BIN`, when the fields were opened with `includeBIN`. Accepted and not used.","type":"string","pattern":"^\\d{6,8}$"},"wallet":{"description":"The card came from TRX's Apple Pay or Google Pay button (`onPaymentResult` `data`), not the card fields. Only where wallets are offered — `TRX_WALLETS_ENABLED` and the platform's own host; anywhere else a 400. A wallet's card is never saved and carries no `postal` (a 400 with one).","type":"string","enum":["apple_pay","google_pay"]},"cardSecurity":{"description":"With `wallet` only: the wallet's one-time cryptogram — exactly one of `cavv` and `dsrpCryptogram`, whichever TRX's library gave (both is a 400). Omitted when it gave neither. Good for about a minute; never stored or logged.","anyOf":[{"type":"object","properties":{"cavv":{"type":"string","maxLength":256}},"required":["cavv"]},{"type":"object","properties":{"dsrpCryptogram":{"type":"string","maxLength":256}},"required":["dsrpCryptogram"]}]}},"required":["data","keyId"]},"expectedAmount":{"description":"The amount the page's button showed — the cart's `amountDueNow`, in minor units. When the amount due now is no longer this, nothing is charged and the call is 409 `details.status: amount_changed`. **Required with `card`** (a TRX checkout charges inside this request, so there is no second step in which a changed total could be shown); optional otherwise, and a checkout that omits it behaves exactly as before.","type":"integer","minimum":0,"maximum":9007199254740991},"method":{"description":"How the page is paying — `card`, `apple_pay` or `google_pay` — for the attempt's record (build-plan/278); anything else is none, never a refusal. Never changes the sale.","type":"string"},"analytics":{"description":"PostHog's distinct id (`visitor`) and session id (`session`) for this browser, so the database can find the visit in PostHog (architecture/25 § Analytics). Each is kept when it is 1 to 64 characters with no control character; anything else is dropped, never refused.","type":"object","properties":{"visitor":{"type":"string","maxLength":64},"session":{"type":"string","maxLength":64}}}},"required":["provider"],"example":{"provider":"stripe","email":"sam@example.com","name":"Sam Rivera"}},"StorefrontRescheduleBookingBody":{"type":"object","properties":{"occurrenceId":{"$ref":"#/components/schemas/Uuid"}},"required":["occurrenceId"],"example":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013"}},"StorefrontFeedbackBody":{"type":"object","properties":{"rating":{"$ref":"#/components/schemas/FeedbackRating"},"comment":{"description":"One optional line, asked on a thumbs down. Trimmed; empty is none. A new vote replaces the last comment.","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"analytics":{"description":"PostHog's distinct id (`visitor`) and session id (`session`) for this browser, so the database can find the visit in PostHog (architecture/25 § Analytics). Each is kept when it is 1 to 64 characters with no control character; anything else is dropped, never refused.","type":"object","properties":{"visitor":{"type":"string","maxLength":64},"session":{"type":"string","maxLength":64}}}},"required":["rating"],"example":{"rating":"down","comment":"Could not find Saturday times."}},"FeedbackRating":{"type":"string","enum":["up","down"],"description":"The thumb: `up` or `down`."},"CreateQuestionBody":{"type":"object","properties":{"prompt":{"type":"string","example":"Any wheel experience?"},"helpText":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":{"type":"string","enum":["text","long_text","number","checkbox","radio","select","checkboxes","address"]},"options":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"required":{"type":"boolean"},"maxLength":{"description":"`long_text` only: 50–5,000; 500 when omitted.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"minValue":{"description":"`number` only: the lowest answer taken, from 0.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"maxValue":{"description":"`number` only: the highest answer taken.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"minChoices":{"description":"`checkboxes` only: at least this many picks. It replaces `required` there: 1 or more is required; sending only `required: true` means 1.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"maxChoices":{"description":"`checkboxes` only: at most this many picks, up to the number of options.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["prompt","type"],"example":{"prompt":"Any wheel experience?","type":"radio","options":["None","Some","Lots"],"required":true}},"UpdateQuestionBody":{"type":"object","properties":{"prompt":{"type":"string"},"helpText":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":{"description":"A new type, only until a booking has answered the question (after that 409, `details.code` `question_answered`). Send the new type's options and limits with it; the old type's are dropped.","type":"string","enum":["text","long_text","number","checkbox","radio","select","checkboxes","address"]},"options":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"required":{"type":"boolean"},"maxLength":{"description":"`long_text` only: 50–5,000; 500 when omitted.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"minValue":{"description":"`number` only: the lowest answer taken, from 0.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"maxValue":{"description":"`number` only: the highest answer taken.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"minChoices":{"description":"`checkboxes` only: at least this many picks. It replaces `required` there: 1 or more is required; sending only `required: true` means 1.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"maxChoices":{"description":"`checkboxes` only: at most this many picks, up to the number of options.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"example":{"required":false}},"ReorderImagesBody":{"type":"object","properties":{"ids":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["ids"],"example":{"ids":["550e8400-e29b-41d4-a716-446655440020"]}},"UpdateImageBody":{"type":"object","properties":{"frame":{"anyOf":[{"$ref":"#/components/schemas/ImageFrame"},{"type":"null"}]},"logoShape":{"description":"A logo placement only: square or round are cut from the original to the frame's square; rect is the original as it is.","type":"string","enum":["square","round","rect"]},"logoStyle":{"description":"A logo placement only: a background, border and corner radius baked into the logo file. Null (or the default) clears it. A rect logo with no background or border stays the original as it is.","anyOf":[{"type":"object","properties":{"background":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`#rrggbb` behind the mark (fills a transparent logo), or null for none.","example":null},"border":{"type":"string","enum":["none","thin","thick"],"description":"Thin is 2.5% and thick 5% of the short edge."},"borderColor":{"type":"string","description":"`#rrggbb`; drawn only when border is not none.","example":"#18181b"},"corners":{"type":"number","minimum":0,"maximum":50,"description":"Corner radius in percent of the short edge, for Square and a boxed Original. A Circle is always 50.","example":14}}},{"type":"null"}]}},"required":["frame"],"example":{"frame":{"wide":{"fit":"whole","x":0.5,"y":0.5,"zoom":1,"backdrop":"blur"}}}},"ImageFrame":{"type":"object","properties":{"wide":{"$ref":"#/components/schemas/ShapeFrame"},"square":{"$ref":"#/components/schemas/ShapeFrame"}},"example":{"square":{"fit":"fill","x":0.5,"y":0.32,"zoom":1.6,"backdrop":"blur"}}},"ShapeFrame":{"type":"object","properties":{"fit":{"type":"string","enum":["fill","whole"]},"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1},"zoom":{"type":"number","minimum":0.25,"maximum":4},"backdrop":{"type":"string","enum":["blur","color"]}},"required":["fit","x","y","zoom","backdrop"],"example":{"fit":"fill","x":0.5,"y":0.32,"zoom":1.6,"backdrop":"blur"}},"UploadLocationLogoBody":{"type":"object","properties":{"file":{"type":"string","description":"Logo image (JPEG, PNG, or WebP), already framed to the chosen shape","format":"binary"},"shape":{"description":"Display shape. Auto-detected from aspect ratio when omitted.","type":"string","enum":["square","round","rect"]}},"required":["file"],"example":{"file":"(binary)","shape":"square"}},"CreateJourneyStepBody":{"type":"object","properties":{"name":{"type":"string"},"action":{"type":"string","enum":["message","milestone"]},"mode":{"type":"string","enum":["auto","manual"]},"anchor":{"anyOf":[{"type":"string","enum":["session_start","session_end","step"]},{"type":"null"}]},"anchorStepId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"anyOf":[{"type":"object","properties":{"subject":{"type":"string"},"body":{"type":"string"}},"required":["subject","body"]},{"type":"null"}]},"closes":{"type":"boolean"},"pieceStage":{"description":"The piece stage this step marks (build-plan/277): manual; `picked_up` is a milestone that finishes the booking; one step per stage.","anyOf":[{"type":"string","enum":["in_kiln","ready","picked_up"]},{"type":"null"}]}},"required":["name","action","mode"],"example":{"name":"Thank you","action":"message","mode":"auto","anchor":"session_end","offsetMinutes":120,"message":{"subject":"Thanks for coming","body":"Hi {first name}, thanks for joining {listing}."}}},"UpdateJourneyStepBody":{"type":"object","properties":{"name":{"type":"string"},"mode":{"description":"Collect balance takes timing only: `auto` with `anchor: \"step\"` (at check-in — it counts from the Check in step, offset 0), `auto` with `anchor: \"session_start\"` and `offsetMinutes` from -86400 to -60 (an hour to 60 days before the session), or `manual` (no timer; the desk runs it).","type":"string","enum":["auto","manual"]},"anchor":{"anyOf":[{"type":"string","enum":["session_start","session_end","step"]},{"type":"null"}]},"anchorStepId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"anyOf":[{"type":"object","properties":{"subject":{"type":"string"},"body":{"type":"string"}},"required":["subject","body"]},{"type":"null"}]},"closes":{"type":"boolean"},"pieceStage":{"anyOf":[{"type":"string","enum":["in_kiln","ready","picked_up"]},{"type":"null"}]}},"example":{"name":"Ready for pickup"}},"ReorderJourneyBody":{"type":"object","properties":{"stepIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["stepIds"],"example":{"stepIds":["550e8400-e29b-41d4-a716-446655440025"]}},"SetJourneyStepOffBody":{"type":"object","properties":{"off":{"type":"boolean"}},"required":["off"],"example":{"off":true}},"SetJourneyStepTimingBody":{"type":"object","properties":{"mode":{"anyOf":[{"type":"string","enum":["auto","manual"]},{"type":"null"}]},"anchor":{"description":"Check in: `session_start` or `session_end`; Check out: `session_end`. Collect balance: `step` (at check-in) or `session_start` (before the session).","anyOf":[{"type":"string","enum":["session_start","session_end","step"]},{"type":"null"}]},"offsetMinutes":{"description":"Check in and Check out: 0 to 1440 minutes after their anchor. Collect balance before the session: -86400 to -60 (an hour to 60 days before).","type":"integer","minimum":-86400,"maximum":1440}},"required":["mode"],"example":{"mode":"manual"}},"SetArriveAndLeaveBody":{"type":"object","properties":{"mode":{"description":"Null follows the business on all three steps (a listing only).","anyOf":[{"type":"string","enum":["automatic","manual_checkout","manual"],"description":"automatic: checked in at the start and out at the end by themselves. manual_checkout: checked in by itself, out by the desk — the place stays taken until checked out. manual: the desk checks them in and out, and the check-in sheet asks before checking in over capacity."},{"type":"null"}]},"checkIn":{"anyOf":[{"type":"object","properties":{"anchor":{"type":"string","enum":["session_start","session_end"]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minutes after the anchor, 0 to a day."}},"required":["anchor","offsetMinutes"]},{"type":"null"}]},"checkOut":{"anyOf":[{"type":"object","properties":{"anchor":{"type":"string","enum":["session_start","session_end"]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minutes after the anchor, 0 to a day."}},"required":["anchor","offsetMinutes"]},{"type":"null"}]},"complete":{"type":"string","enum":["auto","manual"]}},"example":{"mode":"manual_checkout"}},"SetListingPiecesBody":{"type":"object","properties":{"on":{"type":"boolean"},"pickupLine":{"description":"The line under the customer's pieces — *Usually ready in about a week.* Omitted keeps it; null clears it.","anyOf":[{"type":"string","maxLength":160},{"type":"null"}]}},"required":["on"],"example":{"on":true,"pickupLine":"Usually ready in about a week. We keep pieces 30 days after they're ready."}},"MarkJourneyStepBody":{"type":"object","properties":{"note":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"acknowledged":{"type":"boolean"}},"description":"Omit `acknowledged` (or send false) to receive the preview. `count` is only valid on a manual step of a booking with more than one spot.","example":{"note":"two bowls","count":6,"acknowledged":true}},"AddPieceBody":{"type":"object","properties":{"photos[]":{"maxItems":5,"type":"array","items":{"type":"string","format":"binary"},"description":"JPEG, PNG or WebP. Kept as JPEG, long edge at most 1600, upright, without its EXIF."},"label":{"type":"string","maxLength":60},"orderLineId":{"description":"A required add-on line on this booking still waiting for a piece. Without a label, the piece takes its name.","$ref":"#/components/schemas/Uuid"}},"example":{"photos[]":["(binary)"],"label":"Giraffe"}},"PieceMoveBody":{"type":"object","properties":{"pieceIds":{"minItems":1,"maxItems":500,"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"stage":{"$ref":"#/components/schemas/PieceStage"},"shelf":{"description":"Where they go (Ready's *Where?*): one of the location's shelves where it keeps them. Ignored for `in_kiln`, which clears the shelf; omitted, each keeps its own.","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"preview":{"description":"Say what the move would do, and move nothing.","type":"boolean"},"note":{"description":"The desk's note at the move — `{note}` in the step's message.","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]}},"required":["pieceIds","stage"],"example":{"pieceIds":["019a0000-0000-7000-8000-0000000002a1"],"stage":"ready","shelf":"B1"}},"PieceStage":{"type":"string","enum":["made","in_kiln","ready","picked_up","not_collected"],"description":"`made` → `in_kiln` → `ready` → `picked_up`, or `ready` → `not_collected`. Made may go straight to Ready; each stage may go back one."},"UpdatePieceBody":{"type":"object","properties":{"label":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"shelf":{"description":"One of the location's shelves where it keeps them, any short text where not; null clears. Refused in the kiln.","anyOf":[{"type":"string","maxLength":40},{"type":"null"}]}},"example":{"label":"Maya's giraffe","shelf":"A2"}},"MovePieceToBookingBody":{"type":"object","properties":{"bookingId":{"description":"Another booking of the business that holds pieces — confirmed, checked in or out, or completed.","$ref":"#/components/schemas/Uuid"}},"required":["bookingId"],"example":{"bookingId":"019a0000-0000-7000-8000-0000000002b2"}},"AddPiecePhotosBody":{"type":"object","properties":{"photos[]":{"minItems":1,"maxItems":5,"type":"array","items":{"type":"string","format":"binary"},"description":"JPEG, PNG or WebP. Kept as JPEG, long edge at most 1600, upright, without its EXIF."},"replacePhotoId":{"description":"A retake: one photo takes this photo's place — the cover, when it was the cover — and this one is deleted.","$ref":"#/components/schemas/Uuid"}},"required":["photos[]"],"example":{"photos[]":["(binary)"]}},"NamePieceBody":{"type":"object","properties":{"pieceId":{"$ref":"#/components/schemas/Uuid"}},"required":["pieceId"],"example":{"pieceId":"019a0000-0000-7000-8000-0000000002a1"}},"PieceShelves":{"type":"object","properties":{"shelves":{"maxItems":100,"type":"array","items":{"type":"string","maxLength":12},"description":"The location's shelf IDs in its order: at most 100 of at most 12 characters, each once."}},"required":["shelves"],"example":{"shelves":["A1","A2","A3","B1","B2","B3"]}},"PlaceAutocompleteBody":{"type":"object","properties":{"query":{"type":"string","description":"Address text typed so far."},"sessionToken":{"type":"string","description":"Autocomplete session token; required once suggestions have been shown."},"timezone":{"description":"Operator IANA timezone (e.g. America/Denver). Biases suggestions near them when the request is server-proxied — Google otherwise sees the datacenter IP.","type":"string"},"kind":{"description":"`address` suggests street addresses only; omitted also suggests businesses.","type":"string","enum":["address"]},"country":{"description":"ISO 3166-1 alpha-2 country; only places there are suggested.","type":"string"}},"required":["query","sessionToken"]},"PlaceDetailsBody":{"type":"object","properties":{"placeId":{"type":"string","description":"The placeId chosen from autocomplete."},"sessionToken":{"type":"string","description":"The same session token from autocomplete."}},"required":["placeId","sessionToken"]},"PlaceResolveBody":{"type":"object","properties":{"query":{"type":"string","description":"A full or partial address to qualify."}},"required":["query"]},"CreateProductBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"shopListed":{"description":"Default true. Pass false for a piece sold only with a class.","type":"boolean"},"taxable":{"description":"Default true.","type":"boolean"},"revenueCategoryId":{"description":"A revenue category of this business — its id, or its name. Null clears it. With one, `taxable` is inert (architecture/31).","anyOf":[{"type":"string"},{"type":"null"}]},"trackInventory":{"description":"Default true. False never runs out and writes no stock rows.","type":"boolean"},"variants":{"description":"At least one. Omitted: one unnamed option with no price, which a draft may have.","minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"description":"An option to keep. Omit it to add a new one.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"description":"Required on every option once there are two, and no two alike. Null on a single-option product.","anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"description":"Unique among the business's live options.","anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"description":"Minor units, zero or more. May be null only while the product is not for sale.","anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"startingStock":{"description":"Create only: how many are on the shelf now, written as one `counted` stock row at `locationId` in the same transaction. Needs `trackInventory`. An update ignores it — stock changes go through the stock verbs.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}}}},"locationId":{"description":"Where it sells (Sold at), and where any `startingStock` is. Optional when the business has one location.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"allLocations":{"description":"Sell it at every location instead. Catalog editors (`catalog.manage`); anyone else is a 403.","type":"boolean"},"offerWith":{"description":"Listings to offer it with, appended to each listing's add-ons in the same transaction (the listing's own `productIds` rules). Another business's listing is a 404.","type":"array","items":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"required":{"type":"boolean"},"maxPerSpot":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["offeringId"]}}},"required":["name"],"description":"Always creates a draft; publish it to put it on sale.","example":{"name":"Bisque piece","shopListed":false,"variants":[{"name":"Mug","sku":"BQ-MUG","priceAmount":1200},{"name":"Bowl","priceAmount":1800}]}},"ReorderProductsBody":{"type":"object","properties":{"ids":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"Every live product id exactly once, in the new order — or, with `locationId`, every one that sells there."},"locationId":{"description":"Reorder what sells at this location (its own and every-location products); the rest keep their places.","$ref":"#/components/schemas/Uuid"}},"required":["ids"],"example":{"ids":["550e8400-e29b-41d4-a716-446655440027"]}},"UpdateProductBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"shopListed":{"type":"boolean"},"taxable":{"type":"boolean"},"revenueCategoryId":{"description":"A revenue category of this business — its id, or its name. Null clears it. With one, `taxable` is inert (architecture/31).","anyOf":[{"type":"string"},{"type":"null"}]},"trackInventory":{"type":"boolean"},"locationId":{"description":"Sold at: one location, or null for every location. Catalog editors (`catalog.manage`). Narrowing to one location is a field error while a listing elsewhere offers it.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"variants":{"description":"Replace-all. Options named by `id` are kept (two kept options may swap SKUs), rows without an id are added, and live options left out are archived.","minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"description":"An option to keep. Omit it to add a new one.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"description":"Required on every option once there are two, and no two alike. Null on a single-option product.","anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"description":"Unique among the business's live options.","anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"description":"Minor units, zero or more. May be null only while the product is not for sale.","anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"startingStock":{"description":"Create only: how many are on the shelf now, written as one `counted` stock row at `locationId` in the same transaction. Needs `trackInventory`. An update ignores it — stock changes go through the stock verbs.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}}}}},"description":"A product that is for sale refuses an edit that would leave an option without a price.","example":{"variants":[{"id":"550e8400-e29b-41d4-a716-446655440028","name":"Mug","sku":"BQ-MUG","priceAmount":1300},{"name":"Plate","priceAmount":1500}]}},"RecordStockBody":{"type":"object","properties":{"locationId":{"description":"Where the stock is. May be omitted when the business has one live location.","$ref":"#/components/schemas/Uuid"},"reason":{"type":"string","enum":["received","adjusted","counted"],"description":"`sold` and `returned` rows are written by sales and refunds, never here."},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"`received`: how many arrived, above zero. `counted`: what is on the shelf now, zero or more; the row carries the difference. `adjusted`: the signed change, never zero; one that takes stock below zero needs a memo."},"memo":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]}},"required":["reason","quantity"],"example":{"reason":"counted","quantity":5,"memo":"Friday count"}},"OrderLineActionBody":{"type":"object","properties":{"expectedEffect":{"$ref":"#/components/schemas/ExpectedMoneyEffect"}},"required":["expectedEffect"],"example":{"expectedEffect":{"currency":"USD","movements":[{"direction":"refund","instrument":"card","amount":1200}]}}},"CreateScheduleBody":{"type":"object","properties":{"name":{"type":"string"},"startDate":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"durationMinutes":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"timezone":{"type":"string"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"until":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"recurrence":{"type":"object","properties":{"freq":{"type":"string","enum":["once","daily","weekly","monthly"]},"interval":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"byWeekday":{"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"startTime":{"type":"string"}},"required":["freq","startTime"]},"rrule":{"type":"string"},"startTime":{"type":"string"}},"required":["name","startDate","durationMinutes"],"example":{"name":"Tuesday evenings","recurrence":{"freq":"weekly","byWeekday":["TU"],"startTime":"18:00"},"startDate":"2026-01-06","durationMinutes":90,"locationId":"550e8400-e29b-41d4-a716-446655440003"}},"UpdateScheduleBody":{"type":"object","properties":{"name":{"type":"string"},"startDate":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"durationMinutes":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"timezone":{"type":"string"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"until":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"recurrence":{"type":"object","properties":{"freq":{"type":"string","enum":["once","daily","weekly","monthly"]},"interval":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"byWeekday":{"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"startTime":{"type":"string"}},"required":["freq","startTime"]},"rrule":{"type":"string"},"startTime":{"type":"string"},"strandedDates":{"$ref":"#/components/schemas/StrandedDecision"}},"example":{"name":"Tuesday evenings — updated"}},"AddCustomerPieceBody":{"type":"object","properties":{"photos":{"minItems":1,"maxItems":5,"type":"array","items":{"type":"string","format":"binary"},"description":"One piece's photos (or `photos[]`): JPEG, PNG or WebP, kept as JPEG with the long edge at most 1600."},"label":{"type":"string","maxLength":60}},"required":["photos"],"example":{"photos":["(binary)"]}},"SignupWaitlistBody":{"type":"object","properties":{"email":{"type":"string","description":"Where to reach the studio when sign-up opens. Stored lowercased."},"studio":{"description":"The studio’s name, if they gave one (up to 120 characters).","type":"string"},"source":{"description":"Which copy of the form was used — `hero` or `end`.","type":"string"},"referrer":{"description":"`document.referrer` when the form was sent, if any.","type":"string"}},"required":["email"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string","description":"Human-readable error message","example":"email is required"},"details":{"description":"Optional structured error details"}},"required":["code","message"],"additionalProperties":false},"v":{"type":"string","pattern":"^\\d+$|^dev$","description":"Deployment build number; dev in source-mode development","example":"1234"}},"required":["error","v"],"additionalProperties":false,"description":"Standard API error response","example":{"error":{"code":"validation","message":"email is required"},"v":"1234"}},"ErrorCode":{"type":"string","enum":["validation","unauthorized","forbidden","not_found","conflict","too_many_requests","internal_error"],"description":"Machine-readable error code","example":"validation"},"AgreementDocument":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"everyListing":{"type":"boolean","description":"On: on every listing at the location, and on each new one. Off: only on the listings that add it."},"show":{"type":"string","enum":["list","popup","full"],"description":"How customers see it. list: named in one box at checkout, one tick for all. popup: opened when they press Book on the listing page, read to the end and ticked. full: its words (or pages) at checkout above Book, with its own tick."},"frequency":{"type":"string","enum":["once","every_booking"],"description":"once: a signed-in customer who agreed is not asked again (a guest always is). every_booking: asked on every booking."},"kind":{"type":"string","enum":["text","pdf"]},"format":{"type":"string","enum":["plain","markdown"],"description":"How the words are written. Copies before Markdown stay plain."},"body":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The words, for a text document; null for a PDF."},"fileName":{"anyOf":[{"type":"string"},{"type":"null"}]},"byteSize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"pageCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"A PDF's pages; null for words."},"agreedCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Customers holding a current acceptance."},"askedBy":{"type":"array","items":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["offeringId","name"],"additionalProperties":false},"description":"The live listings that ask it."},"listingTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The location's live listings."},"path":{"type":"string","description":"Where a customer reads it."},"fromLegacy":{"type":"boolean"}},"required":["id","locationId","name","slug","everyListing","show","frequency","kind","format","body","fileName","byteSize","pageCount","agreedCount","askedBy","listingTotal","path","fromLegacy"],"additionalProperties":false,"description":"A waiver or terms document a location asks customers to agree to","example":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","locationId":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Liability waiver","slug":"liability-waiver","everyListing":true,"show":"list","frequency":"once","kind":"text","format":"markdown","body":"I take part at my own risk.","fileName":null,"byteSize":null,"pageCount":null,"agreedCount":214,"askedBy":[{"offeringId":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Vinyasa Flow"}],"listingTotal":1,"path":"/ash-street-yoga/terms/liability-waiver","fromLegacy":false}},"AssetListResult":{"type":"object","properties":{"assets":{"type":"array","items":{"$ref":"#/components/schemas/Asset"}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"usedBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["assets","total","limit","offset","usedBytes"],"additionalProperties":false,"example":{"assets":[],"total":0,"limit":50,"offset":0,"usedBytes":0}},"Asset":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"kind":{"type":"string","const":"image"},"url":{"type":"string"},"urls":{"type":"object","properties":{"sm":{"type":"string"},"md":{"type":"string"},"lg":{"type":"string"},"orig":{"type":"string"}},"required":["sm","md","lg","orig"],"additionalProperties":false},"width":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"byteSize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"altText":{"anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string"}},"source":{"type":"string","enum":["upload","import"]},"usageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offeringUsageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","kind","url","urls","width","height","byteSize","title","altText","tags","source","usageCount","offeringUsageCount","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440019","kind":"image","url":"https://cdn.example.com/biz/assets/ast/md.webp","urls":{"sm":"https://cdn.example.com/biz/assets/ast/sm.webp","md":"https://cdn.example.com/biz/assets/ast/md.webp","lg":"https://cdn.example.com/biz/assets/ast/lg.webp","orig":"https://cdn.example.com/biz/assets/ast/orig.webp"},"width":1600,"height":1200,"byteSize":120000,"title":"Wheel throwing","altText":"Hands shaping clay on a wheel","tags":["studio"],"source":"upload","usageCount":2,"offeringUsageCount":2,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"Timestamp":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"ISO-8601 timestamp","example":"2026-07-24T12:00:00.000Z"},"AssetDetail":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"kind":{"type":"string","const":"image"},"url":{"type":"string"},"urls":{"type":"object","properties":{"sm":{"type":"string"},"md":{"type":"string"},"lg":{"type":"string"},"orig":{"type":"string"}},"required":["sm","md","lg","orig"],"additionalProperties":false},"width":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"byteSize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"altText":{"anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string"}},"source":{"type":"string","enum":["upload","import"]},"usageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offeringUsageCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"links":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["offering","resource","instructorProfile","membershipPlan","locationLogo","locationHeader","location","product"]},"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["type","id","name"],"additionalProperties":false}}},"required":["id","kind","url","urls","width","height","byteSize","title","altText","tags","source","usageCount","offeringUsageCount","createdAt","updatedAt","archivedAt","links"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440019","kind":"image","url":"https://cdn.example.com/biz/assets/ast/md.webp","urls":{"sm":"https://cdn.example.com/biz/assets/ast/sm.webp","md":"https://cdn.example.com/biz/assets/ast/md.webp","lg":"https://cdn.example.com/biz/assets/ast/lg.webp","orig":"https://cdn.example.com/biz/assets/ast/orig.webp"},"width":1600,"height":1200,"byteSize":120000,"title":"Wheel throwing","altText":"Hands shaping clay on a wheel","tags":["studio"],"source":"upload","usageCount":1,"offeringUsageCount":1,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"links":[{"type":"offering","id":"550e8400-e29b-41d4-a716-446655440004","name":"Wheel Throwing"}]}},"Image":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"assetId":{"$ref":"#/components/schemas/Uuid"},"url":{"type":"string"},"urls":{"type":"object","properties":{"sm":{"type":"string"},"md":{"type":"string"},"lg":{"type":"string"},"orig":{"type":"string"}},"required":["sm","md","lg","orig"],"additionalProperties":false},"width":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sortOrder":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"altText":{"anyOf":[{"type":"string"},{"type":"null"}]},"frame":{"anyOf":[{"$ref":"#/components/schemas/ImageFrameOutput"},{"type":"null"}]},"edgeColor":{"anyOf":[{"type":"string"},{"type":"null"}]},"blurData":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","url","urls","width","height","sortOrder","createdAt","frame","edgeColor","blurData"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440019","assetId":"550e8400-e29b-41d4-a716-446655440019","url":"https://cdn.example.com/biz/listing/lst/img/md.webp","urls":{"sm":"https://cdn.example.com/biz/listing/lst/img/sm.webp","md":"https://cdn.example.com/biz/listing/lst/img/md.webp","lg":"https://cdn.example.com/biz/listing/lst/img/lg.webp","orig":"https://cdn.example.com/biz/listing/lst/img/orig.webp"},"width":1600,"height":1200,"sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z","altText":null,"frame":{"wide":{"fit":"whole","x":0.5,"y":0.5,"zoom":1,"backdrop":"blur"},"square":{"fit":"fill","x":0.5,"y":0.32,"zoom":1.6,"backdrop":"blur"}},"edgeColor":"#1f3a2e","blurData":null}},"BookingImportCreated":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/BookingImportRun"},"system":{"anyOf":[{"type":"string"},{"type":"null"}]},"prefilledFrom":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"aiColumns":{"type":"array","items":{"type":"string"}},"time":{"$ref":"#/components/schemas/BookingImportTimeShare"}},"required":["run","system","prefilledFrom","aiColumns","time"],"additionalProperties":false},"BookingImportRun":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"system":{"anyOf":[{"type":"string"},{"type":"null"}]},"fileName":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"mapping":{"$ref":"#/components/schemas/BookingImportMapping"},"counts":{"$ref":"#/components/schemas/BookingImportCounts"},"flags":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"status":{"type":"string","enum":["mapping","importing","needs_you","done"]},"createdBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"openIssues":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","businessId","locationId","system","fileName","headers","mapping","counts","flags","status","createdBy","createdAt","updatedAt","finishedAt","openIssues"],"additionalProperties":false},"BookingImportMapping":{"type":"object","properties":{"columns":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string","enum":["email","phone","givenName","familyName","name","start","date","startTime","end","lengthMinutes","timeZone","listing","teamMember","location","people","price","paid","paymentStatus","bookingId","status","notes"]},{"type":"string","const":""}]},"description":"Header → field; \"\" is Don’t import. Notes may be several headers’."},"time":{"$ref":"#/components/schemas/BookingImportTimeMappingOutput"},"listings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"listingId":{"$ref":"#/components/schemas/Uuid"},"made":{"type":"boolean","const":true}},"required":["listingId"],"additionalProperties":false},{"type":"object","properties":{"create":{"type":"object","properties":{"type":{"type":"string","enum":["class","session","space"]},"name":{"type":"string"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"priceAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units."},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"slotGranularityMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hostValues":{"type":"array","items":{"type":"string"}}},"required":["type","name","durationMinutes","priceAmount","capacity","slotGranularityMinutes"],"additionalProperties":false}},"required":["create"],"additionalProperties":false},{"type":"object","properties":{"skip":{"type":"boolean","const":true}},"required":["skip"],"additionalProperties":false}]}},"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"personId":{"$ref":"#/components/schemas/Uuid"},"added":{"type":"boolean","const":true}},"required":["personId"],"additionalProperties":false},{"type":"object","properties":{"owner":{"type":"boolean","const":true}},"required":["owner"],"additionalProperties":false},{"type":"object","properties":{"add":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"}},"required":["email","name"],"additionalProperties":false}},"required":["add"],"additionalProperties":false},{"type":"object","properties":{"resourceId":{"$ref":"#/components/schemas/Uuid"},"made":{"type":"boolean","const":true}},"required":["resourceId"],"additionalProperties":false},{"type":"object","properties":{"addRoom":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false}},"required":["addRoom"],"additionalProperties":false},{"type":"object","properties":{"skip":{"type":"boolean","const":true}},"required":["skip"],"additionalProperties":false}]}},"locations":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"}},"required":["locationId"],"additionalProperties":false},{"type":"object","properties":{"skip":{"type":"boolean","const":true}},"required":["skip"],"additionalProperties":false}]}},"sendReminders":{"type":"boolean"},"aiColumns":{"type":"array","items":{"type":"string"}}},"required":["columns","time","listings","people","locations","sendReminders"],"additionalProperties":false},"BookingImportCounts":{"type":"object","properties":{"added":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"held":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"needsYou":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["added","updated","unchanged","held","needsYou","skipped"],"additionalProperties":false},"BookingImportTimeShare":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"read":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"share":{"type":"number"},"ok":{"type":"boolean","description":"Nine in ten read: Continue need not wait for a Format pick."},"dayOrder":{"type":"object","properties":{"inferred":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"ambiguous":{"type":"boolean"}},"required":["inferred","ambiguous"],"additionalProperties":false},"zoneSource":{"anyOf":[{"type":"string","enum":["text","column","setting"]},{"type":"null"}]},"zoneFound":{"anyOf":[{"type":"string"},{"type":"null"}]},"samples":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"read":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["text","read"],"additionalProperties":false}},"unread":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"text":{"type":"string"}},"required":["index","text"],"additionalProperties":false}}},"required":["total","read","share","ok","dayOrder","zoneSource","zoneFound","samples","unread"],"additionalProperties":false},"BookingImportIssue":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"importId":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"kind":{"type":"string","enum":["no_contact","no_name","bad_time","refused"]},"key":{"type":"string"},"facts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"rows":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"status":{"type":"string","enum":["open","resolved","skipped"]},"createdAt":{"type":"string"},"resolvedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","importId","businessId","kind","key","facts","rows","status","createdAt","resolvedAt"],"additionalProperties":false},"BookingImportPatched":{"type":"object","properties":{"run":{"$ref":"#/components/schemas/BookingImportRun"},"made":{"type":"object","properties":{"listings":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"listingId":{"$ref":"#/components/schemas/Uuid"}},"required":["value","listingId"],"additionalProperties":false}},"rooms":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"resourceId":{"$ref":"#/components/schemas/Uuid"}},"required":["value","resourceId"],"additionalProperties":false}},"team":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"personId":{"$ref":"#/components/schemas/Uuid"},"invited":{"type":"boolean"}},"required":["value","personId","invited"],"additionalProperties":false}}},"required":["listings","rooms","team"],"additionalProperties":false}},"required":["run","made"],"additionalProperties":false},"BookingImportMatch":{"type":"object","properties":{"listings":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"match":{"anyOf":[{"type":"object","properties":{"listingId":{"$ref":"#/components/schemas/Uuid"},"by":{"type":"string","enum":["name","model"]}},"required":["listingId","by"],"additionalProperties":false},{"type":"null"}]},"guess":{"type":"object","properties":{"type":{"type":"string","enum":["class","session","space"]},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"priceAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"slotGranularityMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"hostValues":{"type":"array","items":{"type":"string"}},"rows":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["type","durationMinutes","priceAmount","capacity","slotGranularityMinutes","hostValues","rows"],"additionalProperties":false}},"required":["value","count","match","guess"],"additionalProperties":false}},"people":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"match":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]}},"required":["value","count","match"],"additionalProperties":false}},"locations":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"match":{"anyOf":[{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"},"by":{"type":"string","const":"name"}},"required":["locationId","by"],"additionalProperties":false},{"type":"null"}]}},"required":["value","count","match"],"additionalProperties":false}},"catalog":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"ai":{"type":"boolean"}},"required":["listings","people","locations","catalog","ai"],"additionalProperties":false},"BookingImportRowsResult":{"type":"object","properties":{"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BookingImportOutcome"}},"counts":{"$ref":"#/components/schemas/BookingImportCounts"}},"required":["outcomes","counts"],"additionalProperties":false},"BookingImportOutcome":{"type":"object","properties":{"row":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"outcome":{"type":"string","enum":["added","updated","unchanged","held","needs_you","skipped"]},"flags":{"type":"array","items":{"type":"string","enum":["over_seats","double_booked","closed_then","date_added","off_grid","held_without_customer"]},"description":"What went through with a flag (D14) — Done’s Needs a look."},"bookingId":{"$ref":"#/components/schemas/Uuid"},"changed":{"description":"`updated`: what moved — start, listing, people, note, paid, canceled.","type":"array","items":{"type":"string"}},"claimId":{"$ref":"#/components/schemas/Uuid"},"issueId":{"$ref":"#/components/schemas/Uuid"},"kind":{"type":"string","enum":["no_contact","no_name","bad_time","refused"]},"reason":{"type":"string","enum":["already_happened","canceled_in_file","listing_skipped","person_skipped","location_skipped","completed","skipped_by_you"]},"message":{"type":"string"}},"required":["row","outcome","flags"],"additionalProperties":false},"BookingImportIssueResult":{"type":"object","properties":{"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BookingImportOutcome"}},"counts":{"$ref":"#/components/schemas/BookingImportCounts"},"run":{"$ref":"#/components/schemas/BookingImportRun"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["outcomes","counts","run","issues"],"additionalProperties":false},"BookingImportColumnsMatch":{"type":"object","properties":{"columns":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","enum":["email","phone","givenName","familyName","name","start","date","startTime","end","lengthMinutes","timeZone","listing","teamMember","location","people","price","paid","paymentStatus","bookingId","status","notes"]}},"ai":{"type":"boolean"}},"required":["columns","ai"],"additionalProperties":false},"BookingImportListingsMatch":{"type":"object","properties":{"listings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Uuid"}},"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"personId":{"$ref":"#/components/schemas/Uuid"}},"required":["personId"],"additionalProperties":false},{"type":"object","properties":{"resourceId":{"$ref":"#/components/schemas/Uuid"}},"required":["resourceId"],"additionalProperties":false}]}},"ai":{"type":"boolean"}},"required":["listings","people","ai"],"additionalProperties":false},"CreateBusinessResult":{"type":"object","properties":{"business":{"$ref":"#/components/schemas/Business"},"location":{"$ref":"#/components/schemas/Location"}},"required":["business","location"],"additionalProperties":false,"example":{"business":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"location":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}}},"Business":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"slugIsCustom":{"type":"boolean"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"url":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactEmail":{"$ref":"#/components/schemas/Email"},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"accountantEmail":{"anyOf":[{"$ref":"#/components/schemas/Email"},{"type":"null"}]},"stripeAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"stripeChargesEnabled":{"type":"boolean"},"stripePayoutsEnabled":{"type":"boolean"},"stripeOnboardingStatus":{"$ref":"#/components/schemas/StripeOnboardingStatus"},"paymentsProvider":{"type":"string","enum":["stripe","trx"],"description":"The card provider this business takes money through; read-only (build-plan/200)"},"platformFeeBps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Per-merchant platform fee override in bps; null = PLATFORM_FEE_BPS"},"feeMode":{"type":"string","enum":["absorb","split","pass"],"description":"Who bears the platform fee (build-plan/70)"},"feeCustomerPct":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Customer share percent when feeMode is split (0–100, steps of 5)"},"feeModeAvailable":{"type":"boolean","description":"Whether feeMode may be chosen — false on a TRX business, where there is no platform fee and feeMode stays absorb (build-plan/200 D1)"},"currency":{"$ref":"#/components/schemas/CurrencyCode"},"locale":{"$ref":"#/components/schemas/Locale"},"dateFormat":{"$ref":"#/components/schemas/DateFormat"},"businessType":{"anyOf":[{"$ref":"#/components/schemas/BusinessType"},{"type":"null"}]},"enabledModules":{"type":"array","items":{"type":"string","enum":["classes","sessions","spaces","memberships","products"]},"description":"Optional product modules shown in admin chrome (architecture/11)"},"modulesSelected":{"type":"boolean","description":"True once the business has chosen what it sells — at setup or in Settings"},"deskPaymentMethods":{"type":"array","items":{"type":"string","enum":["card","link","cash"]},"description":"Settings → Payments: which of PlaceFull’s own ways — card now, pay link, cash — the desk may take (architecture/24). Paid-elsewhere methods are the business’s channels."},"bookingHorizonDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Booking-rule default: how far ahead people can book, in days. Listings inherit unless they override."},"bookingCutoffMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Booking-rule default: minutes before start when booking closes; 0 = at start."},"cancellationCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Booking-rule default: hours before start when cancelling closes; null = any time; -1 = no cancellation."},"rescheduleCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Booking-rule default: hours before start when changing the time closes; null = until the start; -1 = no changes."},"spotsLeft":{"type":"string","enum":["few","always"],"description":"Spots left on a storefront time: few — \"N spots left\" at five or fewer, once one is taken; always — whenever a time has spots left. A listing may set its own (build-plan/238)."},"bookingMessages":{"type":"string","enum":["email","sms"],"description":"How customers hear about their bookings — email, or text when we have their mobile (architecture/17 § Texts)."},"requireBookingPhone":{"type":"boolean","description":"Settings → Booking → Contact. On, checkout requires a phone number when the cart holds a booking or a series. Email is always required. Default false."},"guestMarketingConsentDefault":{"type":"boolean","description":"Settings → Booking → Contact. On, guests see the news checkbox ticked at checkout. They can untick it. Default true. The words are Settings → Messaging. Signed-in shoppers who have not already opted in still see it unticked."},"words":{"$ref":"#/components/schemas/StudioWordsOutput"},"messages":{"$ref":"#/components/schemas/StudioMessages"},"demoMode":{"type":"boolean","description":"Demo mode (build-plan/209): bookings and passes are free and marked demo until it ends or payments go live, either of which deletes the demo data. A new studio starts with it on. Read-only here — POST/DELETE …/demo start and end it."},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","name","slug","slugIsCustom","description","url","contactEmail","contactPhone","accountantEmail","stripeAccountId","stripeChargesEnabled","stripePayoutsEnabled","stripeOnboardingStatus","paymentsProvider","platformFeeBps","feeMode","feeCustomerPct","feeModeAvailable","currency","locale","dateFormat","businessType","enabledModules","modulesSelected","deskPaymentMethods","bookingHorizonDays","bookingCutoffMinutes","cancellationCutoffHours","rescheduleCutoffHours","spotsLeft","bookingMessages","requireBookingPhone","guestMarketingConsentDefault","words","messages","demoMode","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","contactEmail":"hello@sunrise.example.com","contactPhone":"+15559876543","accountantEmail":null,"stripeAccountId":"acct_123","stripeChargesEnabled":true,"stripePayoutsEnabled":true,"stripeOnboardingStatus":"complete","paymentsProvider":"stripe","platformFeeBps":null,"feeMode":"absorb","feeCustomerPct":50,"feeModeAvailable":true,"currency":"USD","locale":"en-US","dateFormat":"MDY","businessType":"art_maker","enabledModules":["instructors","spaces","memberships"],"modulesSelected":true,"deskPaymentMethods":["card","link","cash"],"bookingHorizonDays":90,"bookingCutoffMinutes":0,"cancellationCutoffHours":null,"rescheduleCutoffHours":null,"spotsLeft":"few","bookingMessages":"email","requireBookingPhone":false,"guestMarketingConsentDefault":true,"words":{},"demoMode":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"StripeOnboardingStatus":{"type":"string","enum":["not_started","pending","complete"],"example":"complete"},"StudioMessages":{"type":"object","properties":{"pausedReason":{"type":"string","maxLength":160,"description":"Added after the notice that bookings are paused."},"scheduleEmpty":{"type":"string","maxLength":120,"description":"Shown where the times would be."},"soldOut":{"type":"string","maxLength":200,"description":"Shown above the waitlist when the time they picked is full."},"passwordPrompt":{"type":"string","maxLength":160,"description":"The line above the password field on a listing with a password."},"newsOptIn":{"type":"string","maxLength":80,"description":"The checkbox under email at checkout."},"bookedHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"enrolledHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"payLinkHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"waitlistJoinedNote":{"type":"string","maxLength":300,"description":"Added after their place in line."},"waitlistOfferHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"waitlistOfferNote":{"type":"string","maxLength":300,"description":"Added under the offer. The deadline stays."},"waitlistMissedHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"waitlistMissedNote":{"type":"string","maxLength":300,"description":"Added under our sentence."},"movedHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"movedNote":{"type":"string","maxLength":300,"description":"Added under the new time."},"canceledByStudioHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"canceledByStudioNote":{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},"canceledByCustomerHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"canceledByCustomerNote":{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},"enrollmentCanceledHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"enrollmentCanceledNote":{"type":"string","maxLength":300,"description":"Added under the refund sentence, which stays."},"refundNote":{"type":"string","maxLength":300,"description":"Added under the amount, which stays."},"balanceNote":{"type":"string","maxLength":300,"description":"Added under the amount, which stays."},"membershipHeadline":{"type":"string","maxLength":60,"description":"The headline of the email."},"membershipNote":{"type":"string","maxLength":300,"description":"A welcome under our sentence."},"membershipFailedNote":{"type":"string","maxLength":300,"description":"Added under our sentence about the card."}},"additionalProperties":false,"example":{"soldOut":"We're so popular, it sold out!"}},"Location":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"slugIsCustom":{"type":"boolean"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"type":"string"},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactEmail":{"anyOf":[{"type":"string"},{"type":"null"}]},"timezone":{"type":"string"},"addressTimezone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The IANA zone the address implies (country and state as the address lookup recorded them). Null when it cannot say. A moved address sets `timezone` to it unless the same write names one."},"hoursScheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"defaultConfirmationMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultClassDurationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How long a new class runs, in minutes.","example":60},"defaultAppointmentDurationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How long a new reservation runs, in minutes.","example":60},"logoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Location logo URL (md variant)"},"logoShape":{"anyOf":[{"type":"string","enum":["square","round","rect"]},{"type":"null"}],"description":"How the logo is framed on public pages and emails"},"logoStyle":{"description":"Background, border and corners baked into the logo file. The default when none was set.","$ref":"#/components/schemas/LogoStyle"},"storefrontTheme":{"$ref":"#/components/schemas/StorefrontThemeOutput"},"links":{"$ref":"#/components/schemas/LocationLinks"},"bookingPaused":{"type":"boolean","description":"When true, storefront Book is off; operator and desk booking stay open"},"messages":{"description":"This location's messages. A missing key follows the business, then ours.","$ref":"#/components/schemas/StudioMessages"},"walkInsPublic":{"type":"boolean","description":"When true, the public walk-in bar may render for this location (GET /storefront/slugs/{locationSlug}/live)"},"embedCss":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"This location's own CSS for its plain embed tags, as written; null when none. Served at /embed/v1/{locationSlug}/custom.css, never on a hosted page"},"showAddress":{"type":"boolean","description":"When false, customer pages, emails, and the map omit the address. The stored address still sets the time zone"},"showPhone":{"type":"boolean","description":"When false, customer pages and emails omit the phone. A hidden phone does not fall back to the business"},"showEmail":{"type":"boolean","description":"When false, customer pages and emails omit the email. A hidden email does not fall back to the business"},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","name","slug","slugIsCustom","description","address","lat","lng","country","region","city","postalCode","contactPhone","contactEmail","timezone","addressTimezone","hoursScheduleIds","defaultConfirmationMessage","defaultClassDurationMinutes","defaultAppointmentDurationMinutes","logoUrl","logoShape","logoStyle","storefrontTheme","links","bookingPaused","messages","walkInsPublic","embedCss","showAddress","showPhone","showEmail","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","slug":"sunrise-studio","slugIsCustom":false,"description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"country":"US","region":"CO","city":"Denver","postalCode":"80202","contactPhone":"+15559876543","contactEmail":"downtown@sunrise.example.com","timezone":"America/Denver","addressTimezone":"America/Denver","hoursScheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"defaultConfirmationMessage":"See you at the studio — bring a water bottle.","defaultClassDurationMinutes":60,"defaultAppointmentDurationMinutes":60,"logoUrl":"https://cdn.example/sunrise/logo/md.webp","logoShape":"square","logoStyle":{"background":null,"border":"none","borderColor":"#18181b","corners":14},"storefrontTheme":{"accent":"#2563eb"},"links":{"website":"https://sunrise.example.com","instagram":"https://instagram.com/sunrisestudio"},"bookingPaused":false,"walkInsPublic":false,"embedCss":null,"showAddress":true,"showPhone":true,"showEmail":true,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"LogoStyle":{"type":"object","properties":{"background":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`#rrggbb` behind the mark (fills a transparent logo), or null for none.","example":null},"border":{"type":"string","enum":["none","thin","thick"],"description":"Thin is 2.5% and thick 5% of the short edge."},"borderColor":{"type":"string","description":"`#rrggbb`; drawn only when border is not none.","example":"#18181b"},"corners":{"type":"number","minimum":0,"maximum":50,"description":"Corner radius in percent of the short edge, for Square and a boxed Original. A Circle is always 50.","example":14}},"required":["background","border","borderColor","corners"],"additionalProperties":false,"example":{"background":null,"border":"none","borderColor":"#18181b","corners":14}},"LocationLinks":{"type":"object","properties":{"website":{"description":"The location’s website; the page falls back to the business’s when absent — an https URL, normalised on write.","type":"string"},"instagram":{"description":"Instagram — an https URL, normalised on write.","type":"string"},"facebook":{"description":"Facebook — an https URL, normalised on write.","type":"string"},"tiktok":{"description":"TikTok — an https URL, normalised on write.","type":"string"},"youtube":{"description":"YouTube — an https URL, normalised on write.","type":"string"},"x":{"description":"X — an https URL, normalised on write.","type":"string"},"linkedin":{"description":"LinkedIn — an https URL, normalised on write.","type":"string"},"yelp":{"description":"Yelp — an https URL, normalised on write.","type":"string"},"google":{"description":"Google — an https URL, normalised on write.","type":"string"}},"additionalProperties":false,"example":{"website":"https://ashstreetyoga.com","instagram":"https://instagram.com/ashstreetyoga"}},"Booking":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"type":"string"},"enrollmentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"subscriptionMembershipId":{"description":"A subscription's session (build-plan/280): the subscription it belongs to.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookedBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"channel":{"type":"string","enum":["online","staff","api"]},"source":{"anyOf":[{"type":"string","enum":["page","embed","embed_schedule","desk","agent","api","import"]},{"type":"null"}],"description":"Where this booking came from (architecture/06 § source): page | embed | embed_schedule | desk | agent | api | import (Bookings → Import, build-plan/285). Null predates this column, or a waitlist promotion, and reads Unknown — there is no backfill."},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["held","confirmed","checked_in","checked_out","completed","canceled","no_show"]},"checkedInAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"checkedOutAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"completedAt":{"description":"Set when the journey's Complete ran (architecture/06 § 5). After it, only refunds and payments change the booking.","anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"holdExpiresAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"priceSnapshot":{"$ref":"#/components/schemas/BookingQuote"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"appliedMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditsApplied":{"$ref":"#/components/schemas/MoneyAmount"},"platformFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"customerFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"taxAmount":{"$ref":"#/components/schemas/MoneyAmount"},"feeBpsSnapshot":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"feeModeSnapshot":{"anyOf":[{"type":"string","enum":["absorb","split","pass"]},{"type":"null"}]},"cancellationReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"reference":{"type":"string"},"paidElsewhere":{"description":"Paid through another system — Groupon, the POS (architecture/24 § Paid elsewhere, § Closing out). Nothing is owed here for it and the ledger never sees it.","anyOf":[{"type":"object","properties":{"channelId":{"$ref":"#/components/schemas/Uuid"},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"label":{"type":"string"},"amount":{"description":"What was closed out through the method after booking (a balance); 0 when the whole line was paid elsewhere from the hold.","$ref":"#/components/schemas/MoneyAmount"}},"required":["channelId","reference","label"],"additionalProperties":false},{"type":"null"}]},"note":{"description":"The note the import wrote (build-plan/285 D11): the file’s Notes columns, one line each (Label: VIP). Null with none.","anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"amountPaid":{"$ref":"#/components/schemas/MoneyAmount"},"amountDue":{"$ref":"#/components/schemas/MoneyAmount"},"positions":{"type":"array","items":{"$ref":"#/components/schemas/BookingAssignedPosition"}},"closedBy":{"description":"Detail read only (build-plan/249): the closure over this booking, in the Calendar's words (Closed · block). Null when the time is open. Computed at read time; there is no column. Absent on a list.","anyOf":[{"type":"string"},{"type":"null"}]},"checkOutReleasesSpace":{"description":"Detail read only (build-plan/250): this booking is its date's only seat-holder and the date has not ended, so checking out ends the held window now and frees the room or table. Absent on a list.","type":"boolean"}},"required":["id","businessId","locationId","offeringId","occurrenceId","customerId","bookedBy","cartId","channel","source","partySize","status","holdExpiresAt","priceSnapshot","amountTotal","currency","appliedMembershipId","creditMembershipId","creditsApplied","platformFeeAmount","customerFeeAmount","feeBpsSnapshot","feeModeSnapshot","cancellationReason","idempotencyKey","reference","createdAt","updatedAt","amountPaid","amountDue"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[]}},"BookingQuote":{"type":"object","properties":{"base":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"adjustments":{"type":"array","items":{"$ref":"#/components/schemas/QuoteAdjustment"}},"discountedSubtotal":{"$ref":"#/components/schemas/MoneyAmount"},"creditsApplied":{"$ref":"#/components/schemas/MoneyAmount"},"amountDueTotal":{"$ref":"#/components/schemas/MoneyAmount"},"amountDueNow":{"$ref":"#/components/schemas/MoneyAmount"},"amountDueLater":{"$ref":"#/components/schemas/MoneyAmount"},"creditRedemptionAvailable":{"type":"boolean"},"appliedMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"platformFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"customerFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"feeBps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"feeMode":{"type":"string","enum":["absorb","split","pass"]},"taxes":{"type":"array","items":{"type":"object","properties":{"taxRateId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"ratePpm":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"$ref":"#/components/schemas/MoneyAmount"},"base":{"$ref":"#/components/schemas/MoneyAmount"}},"required":["taxRateId","name","ratePpm","amount"],"additionalProperties":false}},"taxTotal":{"$ref":"#/components/schemas/MoneyAmount"},"taxNow":{"$ref":"#/components/schemas/MoneyAmount"},"taxLater":{"$ref":"#/components/schemas/MoneyAmount"},"parts":{"type":"array","items":{"type":"object","properties":{"revenueCategoryId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"base":{"$ref":"#/components/schemas/MoneyAmount"},"taxRateIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["revenueCategoryId","name","base","taxRateIds"],"additionalProperties":false}}},"required":["base","currency","partySize","adjustments","discountedSubtotal","creditsApplied","amountDueTotal","amountDueNow","amountDueLater","creditRedemptionAvailable","appliedMembershipId","creditMembershipId","platformFeeAmount","customerFeeAmount","feeBps","feeMode"],"additionalProperties":false,"example":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]}},"Currency":{"type":"string","minLength":3,"maxLength":3,"description":"ISO-4217 currency code","example":"USD"},"QuoteAdjustment":{"type":"object","properties":{"kind":{"type":"string","enum":["discount","booking_fee","tax","paid_elsewhere","demo","subscription"]},"membershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"membershipPlanId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"benefitId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"discountId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"code":{"anyOf":[{"type":"string"},{"type":"null"}]},"channelId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"label":{"type":"string"},"amount":{"$ref":"#/components/schemas/MoneyAmount"}},"required":["kind","membershipId","membershipPlanId","benefitId","label","amount"],"additionalProperties":false,"example":{"kind":"discount","membershipId":"550e8400-e29b-41d4-a716-446655440011","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","benefitId":"550e8400-e29b-41d4-a716-446655440018","label":"Member 10% off","amount":-300}},"BookingAssignedPosition":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"sortIndex":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","sortIndex","name"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440030","sortIndex":0,"name":"Window"}},"OperatorBookingListResult":{"type":"object","properties":{"timezone":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"page":{"type":"object","properties":{"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["offset","limit","total"],"additionalProperties":false},"days":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string"},"bookings":{"type":"array","items":{"$ref":"#/components/schemas/OperatorBooking"}}},"required":["day","bookings"],"additionalProperties":false}}},"required":["timezone","days"],"additionalProperties":false,"example":{"timezone":"America/Denver","from":"2026-07-27","to":"2026-08-03","days":[{"day":"2026-08-01","bookings":[{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[],"offeringName":"Morning Flow","partyLabel":null,"spots":[],"customerName":"Alex Rivera","customerEmail":"alex@example.com","customerPhone":null,"occurrenceStartsAt":"2026-08-01T18:00:00.000Z","occurrenceEndsAt":"2026-08-01T19:00:00.000Z","instructorNames":"Alex Rivera","latestPaymentStatus":null,"amountRefunded":0,"balanceCollection":null}]}]}},"OperatorBooking":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"type":"string"},"enrollmentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"subscriptionMembershipId":{"description":"A subscription's session (build-plan/280): the subscription it belongs to.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookedBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"channel":{"type":"string","enum":["online","staff","api"]},"source":{"anyOf":[{"type":"string","enum":["page","embed","embed_schedule","desk","agent","api","import"]},{"type":"null"}],"description":"Where this booking came from (architecture/06 § source): page | embed | embed_schedule | desk | agent | api | import (Bookings → Import, build-plan/285). Null predates this column, or a waitlist promotion, and reads Unknown — there is no backfill."},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["held","confirmed","checked_in","checked_out","completed","canceled","no_show"]},"checkedInAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"checkedOutAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"completedAt":{"description":"Set when the journey's Complete ran (architecture/06 § 5). After it, only refunds and payments change the booking.","anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"holdExpiresAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"priceSnapshot":{"$ref":"#/components/schemas/BookingQuote"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"appliedMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditsApplied":{"$ref":"#/components/schemas/MoneyAmount"},"platformFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"customerFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"taxAmount":{"$ref":"#/components/schemas/MoneyAmount"},"feeBpsSnapshot":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"feeModeSnapshot":{"anyOf":[{"type":"string","enum":["absorb","split","pass"]},{"type":"null"}]},"cancellationReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"reference":{"type":"string"},"paidElsewhere":{"description":"Paid through another system — Groupon, the POS (architecture/24 § Paid elsewhere, § Closing out). Nothing is owed here for it and the ledger never sees it.","anyOf":[{"type":"object","properties":{"channelId":{"$ref":"#/components/schemas/Uuid"},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"label":{"type":"string"},"amount":{"description":"What was closed out through the method after booking (a balance); 0 when the whole line was paid elsewhere from the hold.","$ref":"#/components/schemas/MoneyAmount"}},"required":["channelId","reference","label"],"additionalProperties":false},{"type":"null"}]},"note":{"description":"The note the import wrote (build-plan/285 D11): the file’s Notes columns, one line each (Label: VIP). Null with none.","anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"amountPaid":{"$ref":"#/components/schemas/MoneyAmount"},"amountDue":{"$ref":"#/components/schemas/MoneyAmount"},"positions":{"type":"array","items":{"$ref":"#/components/schemas/BookingAssignedPosition"}},"closedBy":{"description":"Detail read only (build-plan/249): the closure over this booking, in the Calendar's words (Closed · block). Null when the time is open. Computed at read time; there is no column. Absent on a list.","anyOf":[{"type":"string"},{"type":"null"}]},"checkOutReleasesSpace":{"description":"Detail read only (build-plan/250): this booking is its date's only seat-holder and the date has not ended, so checking out ends the held window now and frees the room or table. Absent on a list.","type":"boolean"},"offeringName":{"type":"string"},"offeringType":{"type":"string","enum":["class","session","space"]},"offeringColor":{"type":"string","description":"The color the listing wears on the calendar, bookings, and today. A #rrggbb, or a category name."},"offeringIcon":{"anyOf":[{"type":"string","enum":["artboard","glass-full","wheel","hands","mug","brush","glass","flame","pencil","cookie","palette","door","moon","heart","users","kid","senior","tent","series","tools","cake","lock","team","school","fundraiser","tree","pumpkin","leaf","hearts","egg","flower","tie","star","confetti","skull","sun","ticket","gift-card","building","cash","beach","graduation-cap","dumbbell","kettlebell","biceps","person-standing","heart-pulse","timer","zap","bike","footprints","waves","user","baby","paintbrush","amphora","hand","scissors","sparkles","music","mic","camera","utensils","coffee","book"]},{"type":"null"}],"description":"The icon the listing wears there. Null is the kind's own glyph."},"roomName":{"description":"A room booking's room — its date's own, which the desk may have moved it to (build-plan/238 T4). Present only on a `space` booking.","type":"string"},"exclusive":{"type":"boolean","description":"The listing books the whole date — a rental or a buyout. Seat is not offered."},"tabledRoom":{"type":"boolean","description":"The date's room has live tables, so the record can open the floor on this party (build-plan/241)."},"tables":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The table's own name; null names it by its place."},"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Its place among the room's live tables — Table {index + 1}."},"seats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many of this party sit there."}},"required":["id","name","index","seats"],"additionalProperties":false},"description":"The tables the party sits at, in the room’s order; empty when none (architecture/11 § Where a party sits)."},"tableLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Where the party sits, as staff read it: \"Table 3\", \"Table 1 (4) + Table 2 (2)\", or \"No table\" for a live party in a tabled room nobody has seated. Null where tables do not apply."},"partyLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What a named price bought, in place of a spot count — \"Painter · 1 person\" (architecture/03 § Prices). Null for the base alone."},"spots":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["label","count"],"additionalProperties":false},"description":"Each price this booking holds now, name and how many — counts from the live selection, labels from the price that was paid. Empty for the unnamed base alone (architecture/03 § Prices, build-plan/241)."},"priceSelection":{"description":"What it holds among the listing’s prices, by price id (null the first price); null is the base alone. Edit a booking reads it (build-plan/288).","anyOf":[{"type":"array","items":{"type":"object","properties":{"tierId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["tierId","quantity"],"additionalProperties":false}},{"type":"null"}]},"paidForPartySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Spots the price snapshot was paid for. After Keep lowers the count, the record can say Paid for N while partySize is the live count (build-plan/241)."},"customerName":{"type":"string"},"customerEmail":{"$ref":"#/components/schemas/Email"},"customerPhone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's phone, null when absent."},"occurrenceStartsAt":{"$ref":"#/components/schemas/Timestamp"},"occurrenceEndsAt":{"$ref":"#/components/schemas/Timestamp"},"instructorNames":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Who the booked time is with — \"Sam\", or \"Sam + Dana\" for a co-taught class."},"checkInManual":{"description":"The booking's pending Check in waits for a person — no timer (architecture/29 § Retiming).","type":"boolean"},"checkOutManual":{"description":"The booking's pending Check out waits for a person — no timer.","type":"boolean"},"latestPaymentStatus":{"anyOf":[{"type":"string","enum":["requires_action","authorized","captured","canceled","failed","refunded","partially_refunded"]},{"type":"null"}]},"amountRefunded":{"$ref":"#/components/schemas/MoneyAmount"},"seriesSessionIndex":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"seriesSessionCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"answers":{"type":"array","items":{"type":"object","properties":{"questionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"prompt":{"type":"string"},"type":{"type":"string"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"],"additionalProperties":false}]}},"required":["questionId","prompt","type","value"],"additionalProperties":false}},"agreementsMissing":{"type":"array","items":{"type":"string"}},"agreements":{"$ref":"#/components/schemas/BookingAgreements"},"payLink":{"$ref":"#/components/schemas/BookingPayLink"},"addOns":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The product — \"Bisque piece\"."},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The option — \"Mug\"; null on a single-option product."},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fulfilled":{"type":"boolean","description":"Handed over — at check-in, or at the listing's closing journey step."}},"required":["name","variantName","quantity","fulfilled"],"additionalProperties":false}},"balanceCollection":{"anyOf":[{"type":"object","properties":{"runAt":{"$ref":"#/components/schemas/Timestamp"},"status":{"type":"string","enum":["scheduled","failed"]}},"required":["runAt","status"],"additionalProperties":false},{"type":"null"}]},"savedCard":{"anyOf":[{"type":"object","properties":{"brand":{"type":"string"},"last4":{"type":"string"}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"offeringPieces":{"type":"boolean"},"pieces":{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"byStage":{"type":"object","properties":{"made":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"inKiln":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"ready":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"pickedUp":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"notCollected":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["made","inKiln","ready","pickedUp","notCollected"],"additionalProperties":false}},"required":["count","byStage"],"additionalProperties":false},"piecesReady":{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"shelves":{"type":"array","items":{"type":"string"},"description":"The shelves its ready pieces sit on, each once; empty when none has one."},"covers":{"maxItems":2,"type":"array","items":{"type":"string","format":"uri"},"description":"Signed reads (an hour) of up to two pieces' cover photos."},"readyPieceIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"Every ready piece — what Picked up moves."}},"required":["count","shelves","covers","readyPieceIds"],"additionalProperties":false},"moneyEffects":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["booking.confirm","booking.collect_balance","booking.cancel","booking.complete","payment.refund","membership.record_payment","enrollment.cancel","occurrence.cancel"]},"currency":{"type":"string"},"movements":{"type":"array","items":{"type":"object","properties":{"direction":{"type":"string","enum":["charge","refund","forfeit"]},"instrument":{"type":"string","enum":["card","cash","credits"]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"label":{"type":"string"}},"required":["direction","instrument","amount","label"],"additionalProperties":false}},"requiresApproval":{"type":"boolean"},"summary":{"type":"string"}},"required":["action","currency","movements","requiresApproval","summary"],"additionalProperties":false}}},"required":["id","businessId","locationId","offeringId","occurrenceId","customerId","bookedBy","cartId","channel","source","partySize","status","holdExpiresAt","priceSnapshot","amountTotal","currency","appliedMembershipId","creditMembershipId","creditsApplied","platformFeeAmount","customerFeeAmount","feeBpsSnapshot","feeModeSnapshot","cancellationReason","idempotencyKey","reference","createdAt","updatedAt","amountPaid","amountDue","offeringName","offeringType","offeringColor","offeringIcon","exclusive","tabledRoom","tables","tableLabel","partyLabel","spots","paidForPartySize","customerName","customerEmail","customerPhone","occurrenceStartsAt","occurrenceEndsAt","instructorNames","latestPaymentStatus","amountRefunded"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[],"offeringName":"Morning Flow","partyLabel":null,"spots":[],"customerName":"Alex Rivera","customerEmail":"alex@example.com","customerPhone":null,"occurrenceStartsAt":"2026-08-01T18:00:00.000Z","occurrenceEndsAt":"2026-08-01T19:00:00.000Z","instructorNames":"Alex Rivera","latestPaymentStatus":null,"amountRefunded":0,"balanceCollection":null}},"BookingAgreements":{"type":"object","properties":{"documents":{"type":"array","items":{"type":"object","properties":{"documentId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"frequency":{"type":"string","enum":["once","every_booking"]},"agreed":{"anyOf":[{"type":"object","properties":{"at":{"$ref":"#/components/schemas/Timestamp"},"source":{"type":"string","enum":["checkout","staff","link"]},"byName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["at","source","byName"],"additionalProperties":false},{"type":"null"}]}},"required":["documentId","name","kind","frequency","agreed"],"additionalProperties":false}},"lastRequest":{"anyOf":[{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms","copy"]},"toMasked":{"anyOf":[{"type":"string"},{"type":"null"}]},"sentAt":{"$ref":"#/components/schemas/Timestamp"},"delivery":{"anyOf":[{"type":"string","enum":["sent","delivered","opened","bounced","failed"]},{"type":"null"}]},"deliveredAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"openedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["channel","toMasked","sentAt","delivery"],"additionalProperties":false},{"type":"null"}]},"canSend":{"type":"boolean"},"canText":{"type":"boolean"}},"required":["documents","lastRequest","canSend","canText"],"additionalProperties":false,"description":"Each waiver or terms document the booking asks for, agreed or not (and how), the last link sent and how it landed, and whether a link can still be sent.","example":{"documents":[{"documentId":"01a08bee-0000-7000-8000-000000000001","name":"Liability waiver","kind":"text","frequency":"once","agreed":{"at":"2026-10-15T14:31:00.000Z","source":"link","byName":null}},{"documentId":"01a08bee-0000-7000-8000-000000000002","name":"Studio rules","kind":"text","frequency":"every_booking","agreed":null}],"lastRequest":{"channel":"sms","toMasked":"•••• 2030","sentAt":"2026-10-15T14:14:00.000Z","delivery":"delivered"},"canSend":true,"canText":true}},"BookingPayLink":{"type":"object","properties":{"canSend":{"type":"boolean"},"canText":{"type":"boolean"},"lastRequest":{"anyOf":[{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms"]},"toMasked":{"anyOf":[{"type":"string"},{"type":"null"}]},"sentAt":{"$ref":"#/components/schemas/Timestamp"},"delivery":{"type":"string","enum":["sent","delivered","opened","bounced","failed"]},"deliveredAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"openedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["channel","toMasked","sentAt","delivery"],"additionalProperties":false},{"type":"null"}]}},"required":["canSend","canText","lastRequest"],"additionalProperties":false,"description":"Whether a held booking can be sent its pay link, whether a text can go, and the last send with how it landed.","example":{"canSend":true,"canText":false,"lastRequest":{"channel":"email","toMasked":"s•••@example.com","sentAt":"2026-10-15T18:00:00.000Z","delivery":"delivered"}}},"ScheduleCapacityByStatus":{"type":"object","properties":{"held":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"confirmed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"completed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"noShow":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"elsewhere":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["held","confirmed","completed","noShow","elsewhere"],"additionalProperties":false,"example":{"held":0,"confirmed":3,"completed":1,"noShow":0,"elsewhere":0}},"StrandedReason":{"anyOf":[{"type":"string","enum":["schedule","closure"]},{"type":"null"}],"description":"Operator reads only. `schedule`: no bound rule produces this booked date any more (a day dropped, a time moved, the rule ended, the class archived). `closure`: the rule produces it but a closure or time off removed it. It still runs for the people on it; nobody new can book it. Null when the rule produces the date.","example":null},"PayLinkCart":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"token":{"type":"string"},"businessId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["open","checked_out","canceled"]},"channel":{"type":"string","enum":["online","staff","api"]},"createdBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"currency":{"$ref":"#/components/schemas/Currency"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerFirstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"checkedOutAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CartItem"}},"amountDueNow":{"$ref":"#/components/schemas/MoneyAmount"},"amountDueLater":{"$ref":"#/components/schemas/MoneyAmount"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"amountTax":{"$ref":"#/components/schemas/MoneyAmount"},"amountCustomerFee":{"$ref":"#/components/schemas/MoneyAmount"},"feeLabel":{"type":"string","enum":["booking","service"],"description":"The fee row reads \"Booking fee\" (`booking`) when any booking or series item is in the cart, \"Service fee\" (`service`) otherwise."},"agreements":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"$ref":"#/components/schemas/Uuid"},"ask":{"type":"string","enum":["checkbox","must_read"]}},"required":["id","name","kind","path","contentId","ask"],"additionalProperties":false}},"agreementsAgreed":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"$ref":"#/components/schemas/Uuid"},"ask":{"type":"string","enum":["checkbox","must_read"]}},"required":["id","name","kind","path","contentId","ask"],"additionalProperties":false}},"memberOffer":{"anyOf":[{"$ref":"#/components/schemas/StorefrontMemberOffer"},{"type":"null"}]},"discountCode":{"anyOf":[{"type":"object","properties":{"code":{"type":"string"},"state":{"type":"string","enum":["applied","no_match"]},"amount":{"$ref":"#/components/schemas/MoneyAmount"}},"required":["code","state","amount"],"additionalProperties":false},{"type":"null"}]},"url":{"type":"string","format":"uri"},"qrSvg":{"type":"string","description":"Inline SVG QR of `url` for scan-to-pay at the counter."}},"required":["id","token","businessId","status","channel","createdBy","currency","note","customerFirstName","checkedOutAt","createdAt","items","amountDueNow","amountDueLater","amountTotal","amountCustomerFee","feeLabel","url","qrSvg"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440022","token":"wS3nQ8xKf1JqL7ZtB4gYcR2v","businessId":"550e8400-e29b-41d4-a716-446655440002","status":"open","createdBy":null,"channel":"online","currency":"USD","note":null,"customerFirstName":null,"checkedOutAt":null,"createdAt":"2026-07-24T12:00:00.000Z","items":[{"id":"550e8400-e29b-41d4-a716-446655440023","itemType":"booking","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipPlanId":null,"membershipId":null,"state":"held","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Beginner Wheel Throwing","listingType":"class","listingSlug":"beginner-wheel-throwing","locationSlug":"riverbend-pottery","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T20:00:00.000Z","timezone":"America/Denver","partySize":1,"holdExpiresAt":"2026-08-01T18:00:00.000Z","cancellationCutoffHours":24,"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"taxAmount":0,"customerFeeAmount":0,"currency":"USD","taxes":[],"adjustments":[],"answers":[],"attendeeFirstName":null,"creditsApplied":0}],"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"amountTax":0,"amountCustomerFee":0,"feeLabel":"booking","memberOffer":null,"discountCode":null,"questions":[{"id":"550e8400-e29b-41d4-a716-446655440077","prompt":"Any wheel experience?","helpText":null,"type":"radio","options":["None","Some","Lots"],"required":true}],"url":"https://app.example.com/cart/tok_example","qrSvg":"<svg xmlns=\"http://www.w3.org/2000/svg\">…</svg>"}},"CartItem":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"itemType":{"type":"string","enum":["booking","membership","series","product"]},"bookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"membershipPlanId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"membershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"state":{"type":"string","enum":["held","available","unavailable","confirmed"]},"offeringId":{"type":"string"},"offeringName":{"type":"string"},"listingType":{"anyOf":[{"type":"string","enum":["class","session","space"]},{"type":"null"}]},"heldAway":{"description":"Held off site or online (build-plan/240) — the confirmation names its place; absent at the location.","type":"boolean"},"listingSlug":{"type":"string"},"locationSlug":{"type":"string"},"occurrenceId":{"type":"string"},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"timezone":{"type":"string"},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"holdExpiresAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"cancellationCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"amountDueNow":{"$ref":"#/components/schemas/MoneyAmount"},"amountDueLater":{"$ref":"#/components/schemas/MoneyAmount"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"taxAmount":{"$ref":"#/components/schemas/MoneyAmount"},"customerFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"adjustments":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["discount","booking_fee","tax","paid_elsewhere","demo","subscription"]},"label":{"type":"string"},"amount":{"$ref":"#/components/schemas/MoneyAmount"},"discountId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"code":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["label","amount"],"additionalProperties":false}},"taxes":{"type":"array","items":{"type":"object","properties":{"taxRateId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"ratePpm":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"$ref":"#/components/schemas/MoneyAmount"}},"required":["name","ratePpm","amount"],"additionalProperties":false}},"answers":{"type":"array","items":{"type":"object","properties":{"prompt":{"type":"string"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"],"additionalProperties":false}]}},"required":["prompt","value"],"additionalProperties":false}},"questions":{"description":"Open cart, booking and series lines that ask something: the questions this line asks, in its listing's order (build-plan/239). Each booking keeps its own answers.","type":"array","items":{"$ref":"#/components/schemas/Question"}},"lineAnswers":{"description":"What this line holds, by question id; null when nobody has answered it yet (checkout asks it in place).","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"],"additionalProperties":false}]}},{"type":"null"}]},"answersMissing":{"description":"The question ids this line still owes — Required left open, or an answer the question no longer takes.","type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"attendeeFirstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"creditsApplied":{"$ref":"#/components/schemas/MoneyAmount"},"creditCost":{"description":"Booking lines: credits one spot costs (`offering.credit_cost`).","type":"integer","minimum":0,"maximum":9007199254740991},"passCover":{"description":"Membership lines (MDH-113): the cart items this pass pays for and the credits it keeps — projected while the cart is open, the pass's own balance on a receipt. `creditsLeft` is null for a pass with no credits.","anyOf":[{"type":"object","properties":{"itemIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"creditsLeft":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["itemIds","creditsLeft"],"additionalProperties":false},{"type":"null"}]},"enrollmentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"subscriptionMembershipId":{"description":"A subscription's session (build-plan/280): the subscription it belongs to.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"seriesId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"seriesName":{"anyOf":[{"type":"string"},{"type":"null"}]},"sessionCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"occurrences":{"type":"array","items":{"type":"object","properties":{"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"timezone":{"type":"string"}},"required":["occurrenceId","startsAt","endsAt","timezone"],"additionalProperties":false}},"orderLineId":{"description":"Product lines (architecture/26): the order line this item is.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"description":"The option's name; null on a single-option product.","anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"soldWithBookingId":{"description":"Product lines: the booking this piece is sold with; null for a line bought on its own.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["id","itemType","bookingId","membershipPlanId","state","offeringId","offeringName","listingType","listingSlug","locationSlug","occurrenceId","startsAt","endsAt","timezone","partySize","holdExpiresAt","cancellationCutoffHours","amountDueNow","amountDueLater","amountTotal","customerFeeAmount","currency","adjustments","answers","attendeeFirstName","creditsApplied"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440023","itemType":"booking","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipPlanId":null,"membershipId":null,"state":"held","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Beginner Wheel Throwing","listingType":"class","listingSlug":"beginner-wheel-throwing","locationSlug":"riverbend-pottery","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T20:00:00.000Z","timezone":"America/Denver","partySize":1,"holdExpiresAt":"2026-08-01T18:00:00.000Z","cancellationCutoffHours":24,"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"taxAmount":0,"customerFeeAmount":0,"currency":"USD","taxes":[],"adjustments":[],"answers":[],"attendeeFirstName":null,"creditsApplied":0}},"Question":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"prompt":{"type":"string"},"helpText":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":{"type":"string","enum":["text","long_text","number","checkbox","radio","select","checkboxes","address"],"description":"Short answer `text` (one line, 200 characters) · Long answer `long_text` · Number `number` (a whole number) · Checkbox `checkbox` (one box; `prompt` is the words beside it; required means it must be ticked, and its answer is true or false) · Pick one `radio` · Dropdown `select` · Pick any `checkboxes` · Address `address`."},"options":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"required":{"type":"boolean"},"maxLength":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Long answer (`long_text`) only: its character limit, 50–5,000. Null on every other type."},"minValue":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"`number` only: the lowest answer taken. Null when open."},"maxValue":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"`number` only: the highest answer taken. Null when open."},"minChoices":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Pick any (`checkboxes`) only: at least this many picks. At least 1 is what makes it required."},"maxChoices":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Pick any (`checkboxes`) only: at most this many picks."}},"required":["id","prompt","helpText","type","options","required","maxLength","minValue","maxValue","minChoices","maxChoices"],"additionalProperties":false,"description":"A checkout question from the business catalog (architecture/16 § Questions at checkout)","example":{"id":"550e8400-e29b-41d4-a716-446655440077","prompt":"Any wheel experience?","helpText":"Helps us group the class.","type":"radio","options":["None","Some","Lots"],"required":true,"maxLength":null,"minValue":null,"maxValue":null,"minChoices":null,"maxChoices":null}},"StorefrontMemberOffer":{"type":"object","properties":{"priceLabel":{"type":"string"},"cashLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"creditsRemainingLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"discountLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"included":{"type":"boolean"}},"required":["priceLabel","cashLabel","creditsRemainingLabel","discountLabel","included"],"additionalProperties":false,"example":{"priceLabel":"1 credit","cashLabel":null,"creditsRemainingLabel":"9 credits left","discountLabel":null,"included":false}},"PayLinkEmailResult":{"type":"object","properties":{"sent":{"type":"boolean"},"toMasked":{"anyOf":[{"type":"string"},{"type":"null"}]},"reason":{"type":"string","enum":["no_recipient","mail_not_configured","not_open"]},"payLink":{"anyOf":[{"$ref":"#/components/schemas/BookingPayLink"},{"type":"null"}]}},"required":["sent","toMasked"],"additionalProperties":false,"description":"Outcome of emailing a pay link to the cart customer.","example":{"sent":true,"toMasked":"j•••@example.com"}},"BookingAgreementsSendResult":{"type":"object","properties":{"agreements":{"anyOf":[{"$ref":"#/components/schemas/BookingAgreements"},{"type":"null"}]},"url":{"anyOf":[{"type":"string"},{"type":"null"}]},"toMasked":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["agreements","url","toMasked"],"additionalProperties":false,"description":"The block after the send; `url` only when the link was copied, never for a send.","example":{"agreements":null,"url":null,"toMasked":"n•••@example.com"}},"LocationPagePreviewHtml":{"type":"string"},"ListingPagePreviewHtml":{"type":"string"},"PassesPagePreviewHtml":{"type":"string"},"BookingEditPreview":{"type":"object","properties":{"changes":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["listing","time","room","table","spots","price","answers","note","name","email","phone","customer"]},"from":{"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]},"to":{"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"}]},{"type":"null"}]}},"required":["field","from","to"],"additionalProperties":false}},"price":{"anyOf":[{"type":"object","properties":{"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The price it holds now."},"repriced":{"anyOf":[{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"due":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["total","due"],"additionalProperties":false},{"type":"null"}],"description":"Today’s price for the new selection and what would then be owed; null when it keeps its price."},"keepOnly":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why it can only keep its price; null when Repriced is on offer or nothing changes."}},"required":["partySize","currency","total","repriced","keepOnly"],"additionalProperties":false},{"type":"null"}]},"customer":{"anyOf":[{"type":"object","properties":{"outcome":{"type":"string","enum":["unchanged","move","correct","new"]},"target":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"moves":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"passes":{"type":"array","items":{"type":"string"}}},"required":["bookings","passes"],"additionalProperties":false}},"required":["outcome","target","moves"],"additionalProperties":false},{"type":"null"}],"description":"Who the booking ends up with, when the email or Someone else changes it (build-plan/202)."}},"required":["changes","price","customer"],"additionalProperties":false,"example":{"changes":[{"field":"time","from":"2026-10-23T00:00:00.000Z","to":"2026-10-24T20:00:00.000Z"},{"field":"spots","from":2,"to":3},{"field":"price","from":11000,"to":16500}],"price":{"partySize":3,"currency":"usd","total":11000,"repriced":{"total":16500,"due":5500},"keepOnly":null},"customer":null}},"Enrollment":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"seriesId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookedBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"channel":{"type":"string","enum":["online","staff","api"]},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["held","confirmed","canceled"]},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"reference":{"type":"string"},"cancellationReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","locationId","seriesId","customerId","bookedBy","cartId","channel","partySize","status","amountTotal","currency","reference","cancellationReason","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","seriesId":"550e8400-e29b-41d4-a716-446655440024","customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","partySize":1,"status":"confirmed","amountTotal":24000,"currency":"USD","reference":"SR-00000001","cancellationReason":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"ChangeEmailResult":{"type":"object","properties":{"outcome":{"type":"string","enum":["unchanged","move","correct","new"]},"target":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"moves":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"passes":{"type":"array","items":{"type":"string"}}},"required":["bookings","passes"],"additionalProperties":false}},"required":["outcome","target","moves"],"additionalProperties":false,"example":{"outcome":"correct","target":{"id":"0192f1a0-7c3d-7e10-9a2b-000000000041","name":"Jane Smith"},"moves":{"bookings":1,"passes":[]}}},"BookingPlaceChoices":{"type":"object","properties":{"current":{"type":"object","properties":{"roomId":{"$ref":"#/components/schemas/Uuid"},"roomName":{"type":"string"},"tableLabel":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["roomId","roomName","tableLabel"],"additionalProperties":false},"canChangeRoom":{"type":"boolean"},"moves":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"party"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["kind","booked"],"additionalProperties":false}],"description":"What a room change moves: the party alone, or — a class — its whole date, for everyone on it (build-plan/288 D6). `booked` is how many that is.","type":"object"},"rooms":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"current":{"type":"boolean"},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fits":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"why":{"anyOf":[{"type":"string"},{"type":"null"}]},"closedBy":{"description":"The room takes the party, but a closure covers it then (build-plan/249): the closure in the Calendar’s words. The move carries overClosure. Null or absent when the room is open.","anyOf":[{"type":"string"},{"type":"null"}]},"overCapacity":{"description":"The room seats fewer than this would put in it. `fits` stays false — Move refuses it — but Edit a booking takes it, warned (build-plan/288 D6).","type":"boolean"},"tables":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"label":{"type":"string","description":"\"Table 3\", \"Window\" — the floor's own name for it."},"seats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"current":{"type":"boolean"},"fits":{"type":"boolean"},"why":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"\"Kim until 9 PM\", \"Seats 2\"; null when it fits."}},"required":["id","label","seats","current","fits","why"],"additionalProperties":false}}},"required":["id","name","current","capacity","fits","why","tables"],"additionalProperties":false}}},"required":["current","canChangeRoom","moves","rooms"],"additionalProperties":false,"example":{"current":{"roomId":"550e8400-e29b-41d4-a716-446655440040","roomName":"Party Room","tableLabel":"Table 3"},"canChangeRoom":true,"moves":{"kind":"party"},"rooms":[{"id":"550e8400-e29b-41d4-a716-446655440040","name":"Party Room","current":true,"capacity":30,"fits":null,"why":null,"tables":[{"id":"550e8400-e29b-41d4-a716-446655440050","label":"Table 3","seats":6,"current":true,"fits":true,"why":null},{"id":"550e8400-e29b-41d4-a716-446655440051","label":"Window","seats":2,"current":false,"fits":false,"why":"Seats 2"}]},{"id":"550e8400-e29b-41d4-a716-446655440041","name":"Studio","current":false,"capacity":30,"fits":true,"why":null,"tables":[]},{"id":"550e8400-e29b-41d4-a716-446655440042","name":"Nook","current":false,"capacity":4,"fits":false,"why":"Nook holds 4","overCapacity":true,"tables":[]}]}},"BookingRoomChoices":{"type":"object","properties":{"current":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"rooms":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","name","capacity"],"additionalProperties":false}}},"required":["current","rooms"],"additionalProperties":false,"example":{"current":{"id":"550e8400-e29b-41d4-a716-446655440040","name":"Party Room"},"rooms":[{"id":"550e8400-e29b-41d4-a716-446655440041","name":"Studio","capacity":30}]}},"DeskCheckInPreview":{"type":"object","properties":{"early":{"type":"boolean"},"canShiftWindow":{"type":"boolean"},"eligible":{"type":"boolean"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]},"originalStartsAt":{"$ref":"#/components/schemas/Timestamp"},"originalEndsAt":{"$ref":"#/components/schemas/Timestamp"},"defaultEndsAt":{"$ref":"#/components/schemas/Timestamp"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"suggestedTableId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"tables":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"open":{"type":"boolean"},"current":{"type":"boolean"}},"required":["id","name","spots","open","current"],"additionalProperties":false}},"nextOpenAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"freeUntil":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"freeUntilName":{"anyOf":[{"type":"string"},{"type":"null"}]},"overCapacity":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["early","canShiftWindow","eligible","reason","originalStartsAt","originalEndsAt","defaultEndsAt","durationMinutes","suggestedTableId","tables","nextOpenAt","freeUntil","freeUntilName","overCapacity"],"additionalProperties":false,"example":{"early":true,"canShiftWindow":true,"eligible":true,"reason":null,"originalStartsAt":"2026-10-04T17:00:00.000Z","originalEndsAt":"2026-10-04T18:00:00.000Z","defaultEndsAt":"2026-10-04T14:00:00.000Z","durationMinutes":60,"suggestedTableId":"550e8400-e29b-41d4-a716-446655440030","tables":[{"id":"550e8400-e29b-41d4-a716-446655440030","name":"Table 1","spots":4,"open":true,"current":false}],"nextOpenAt":null,"freeUntil":"2026-10-04T16:00:00.000Z","freeUntilName":"Kids Craft Hour","overCapacity":null}},"OccurrencePositionBoard":{"type":"object","properties":{"occurrenceId":{"type":"string"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"offeringName":{"type":"string"},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"timezone":{"type":"string"},"resourceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"resourceName":{"anyOf":[{"type":"string"},{"type":"null"}]},"exclusive":{"type":"boolean"},"mode":{"type":"string","enum":["positions","roster"]},"positionLayout":{"type":"string","enum":["list","grid"]},"capacityTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacityBooked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacityElsewhere":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"waitlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"waitlist":{"type":"array","items":{"type":"object","properties":{"waitlistEntryId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"$ref":"#/components/schemas/Uuid"},"customerName":{"type":"string"},"customerEmail":{"anyOf":[{"type":"string"},{"type":"null"}]},"partySize":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"status":{"type":"string","enum":["waiting","offered"]},"subscription":{"type":"boolean","description":"A place in a subscription's line: it waits for every date at this weekly time, not this one."}},"required":["waitlistEntryId","customerId","customerName","customerEmail","partySize","status","subscription"],"additionalProperties":false},"description":"Who is in line for this date, in order — the date's own waitlist, or for a class sold by subscription the line for its weekly time or every session. `waitlisted` is how many."},"claims":{"type":"array","items":{"$ref":"#/components/schemas/OccurrenceClaimSummary"}},"positions":{"type":"array","items":{"$ref":"#/components/schemas/OccurrencePositionCell"}},"unassignedBookings":{"type":"array","items":{"$ref":"#/components/schemas/OccurrencePositionOccupant"}},"roster":{"type":"array","items":{"$ref":"#/components/schemas/OccurrencePositionOccupant"}},"removable":{"description":"Nothing has happened to this date and it is its rule’s only one: DELETE the date instead of cancelling it (MDH-69).","type":"boolean"},"soloTeam":{"description":"The business is one person, who teaches everything (MDH-70).","type":"boolean"},"walletHolders":{"description":"How many people booked on this date hold their ticket in Apple or Google Wallet now — who a Wallet note reaches (build-plan/262).","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"stranded":{"$ref":"#/components/schemas/StrandedReason"},"share":{"description":"This date’s public link and the words a Facebook event is filled with (build-plan/233). Null when not published, password-protected, cancelled or over.","anyOf":[{"type":"object","properties":{"url":{"type":"string","description":"The listing link with `?time={occurrenceId}` — opens on this date."},"details":{"type":"string","description":"The listing description as plain text; empty when none."},"imageUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The listing’s link-preview photo."},"place":{"type":"string","description":"Location name, with its address when shown to customers."}},"required":["url","details","imageUrl","place"],"additionalProperties":false},{"type":"null"}]}},"required":["occurrenceId","offeringId","offeringName","startsAt","endsAt","timezone","resourceId","resourceName","exclusive","mode","positionLayout","capacityTotal","capacityBooked","capacityElsewhere","waitlisted","waitlist","claims","positions","unassignedBookings","roster","stranded"],"additionalProperties":false,"example":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440010:2026-09-01T17:00:00.000Z","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Morning Flow","startsAt":"2026-07-24T12:00:00.000Z","endsAt":"2026-08-01T18:00:00.000Z","timezone":"America/Denver","resourceId":"550e8400-e29b-41d4-a716-446655440007","resourceName":"Studio A","exclusive":false,"mode":"positions","positionLayout":"list","capacityTotal":20,"capacityBooked":1,"capacityElsewhere":0,"waitlisted":0,"waitlist":[],"claims":[],"positions":[{"id":"550e8400-e29b-41d4-a716-446655440030","sortIndex":0,"name":"Window","occupant":{"bookingId":"550e8400-e29b-41d4-a716-446655440005","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-07-24T12:00:00.000Z"}}],"unassignedBookings":[],"roster":[{"bookingId":"550e8400-e29b-41d4-a716-446655440005","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-07-24T12:00:00.000Z"}],"share":{"url":"https://placefull.ai/downtown/morning-flow?time=550e8400-e29b-41d4-a716-446655440010%3A2026-09-01T17%3A00%3A00.000Z","details":"A slow, steady flow to start the day.","imageUrl":null,"place":"Downtown, 123 Main St, Denver, CO"}}},"OccurrenceClaimSummary":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"channelName":{"type":"string"},"kind":{"type":"string","enum":["door","pos","legacy","marketplace","venue","other"]},"seats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"referenceUrl":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","channelName","kind","seats","label","externalRef","referenceUrl"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440071","channelName":"Square","kind":"pos","seats":2,"label":null,"externalRef":"sqr_123","referenceUrl":null}},"OccurrencePositionCell":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"sortIndex":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"occupant":{"anyOf":[{"$ref":"#/components/schemas/OccurrencePositionOccupant"},{"type":"null"}]}},"required":["id","sortIndex","name","occupant"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440030","sortIndex":0,"name":"Window","occupant":{"bookingId":"550e8400-e29b-41d4-a716-446655440040","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-09-01T17:00:00.000Z","amountDue":0,"amountTotal":2800,"creditsApplied":0,"paidElsewhereLabel":null,"latestPaymentStatus":"captured","currency":"USD","firstVisit":false}}},"OccurrencePositionOccupant":{"type":"object","properties":{"bookingId":{"$ref":"#/components/schemas/Uuid"},"customerName":{"type":"string"},"customerEmail":{"anyOf":[{"type":"string"},{"type":"null"}]},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["held","confirmed","checked_in","checked_out","completed","canceled","no_show"]},"autoCheckinAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"The journey's pending automatic Check in time (architecture/29); null = by hand."},"checkInDueAt":{"description":"Same instant as autoCheckinAt — the name the console reads (MDH-181).","anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"atStep":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"doneCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["name","doneCount","partySize"],"additionalProperties":false},{"type":"null"}]},"noShowRiskBps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"answers":{"type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"prompt":{"type":"string"},"type":{"type":"string"},"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"],"additionalProperties":false}]}},"required":["questionId","prompt","type","value"],"additionalProperties":false}},"addOns":{"description":"The pieces sold with the booking (architecture/26 § Roster) — Need to know lists them beside the answers.","type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The product — \"Bisque piece\"."},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The option — \"Mug\"; null on a single-option product."},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fulfilled":{"type":"boolean","description":"Handed over — at check-in, or at the listing's closing journey step."}},"required":["name","variantName","quantity","fulfilled"],"additionalProperties":false}},"amountDue":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Still owed on this booking, in minor units — the figure the booking read states."},"amountTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The booking's price, in minor units. 0 on a free booking or one a pass covered."},"creditsApplied":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pass credits this booking used. With a zero price, the row says Pass."},"paidElsewhereLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Paid in Groupon, or null when this booking was not paid elsewhere."},"latestPaymentStatus":{"anyOf":[{"type":"string","enum":["requires_action","authorized","captured","canceled","failed","refunded","partially_refunded"]},{"type":"null"}],"description":"The latest payment attempt. failed is the red pill on Check-in."},"currency":{"type":"string"},"agreementsMissing":{"description":"Documents this booking's listing asks for that nobody has agreed to (architecture/33).","type":"array","items":{"type":"string"}},"firstVisit":{"type":"boolean","description":"Nothing on record for this customer but this booking."}},"required":["bookingId","customerName","customerEmail","partySize","status","autoCheckinAt","amountDue","amountTotal","creditsApplied","paidElsewhereLabel","latestPaymentStatus","currency","firstVisit"],"additionalProperties":false,"example":{"bookingId":"550e8400-e29b-41d4-a716-446655440040","customerName":"Ada Lovelace","customerEmail":"ada@example.com","partySize":1,"status":"confirmed","autoCheckinAt":"2026-09-01T17:00:00.000Z","amountDue":0,"amountTotal":2800,"creditsApplied":0,"paidElsewhereLabel":null,"latestPaymentStatus":"captured","currency":"USD","firstVisit":false}},"OccurrenceMessageResult":{"type":"object","properties":{"batchId":{"$ref":"#/components/schemas/Uuid"},"queued":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"skippedNoEmail":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"subject":{"type":"string"},"channels":{"type":"array","items":{"type":"string","enum":["email","wallet"]},"description":"How it went out (build-plan/262)."},"walletHolders":{"description":"When it went by Wallet: how many people hold a ticket for this date in Apple or Google Wallet now.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["batchId","queued","skippedNoEmail","subject","channels"],"additionalProperties":false,"example":{"batchId":"550e8400-e29b-41d4-a716-446655440040","queued":4,"skippedNoEmail":0,"subject":"Morning Flow · Monday, August 31, 10:00 AM","channels":["email","wallet"],"walletHolders":3}},"WalletNoteResult":{"type":"object","properties":{"noteId":{"$ref":"#/components/schemas/Uuid"},"title":{"type":"string"},"holders":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People holding a pass it reaches now — each is notified once."}},"required":["noteId","title","holders"],"additionalProperties":false,"example":{"noteId":"550e8400-e29b-41d4-a716-446655440041","title":"Studio closed Monday","holders":12}},"Channel":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["door","pos","legacy","marketplace","venue","other"]},"referenceLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"referencePattern":{"anyOf":[{"type":"string"},{"type":"null"}]},"referenceUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"enabled":{"type":"boolean"},"referenceMode":{"type":"string","enum":["off","optional","required"]},"icon":{"type":"string","enum":["ticket","store","receipt","gift","tag","globe","building","history"]},"connected":{"type":"boolean"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","name","kind","referenceLabel","referencePattern","referenceUrl","enabled","referenceMode","icon","connected","archivedAt","createdAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440070","businessId":"550e8400-e29b-41d4-a716-446655440000","name":"Square","kind":"pos","referenceLabel":"Square order #","referencePattern":null,"referenceUrl":"https://squareup.com/dashboard/orders/overview/{ref}","enabled":true,"referenceMode":"optional","icon":"store","connected":true,"archivedAt":null,"createdAt":"2026-09-01T17:00:00.000Z"}},"ChannelClaim":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"type":"string"},"channelId":{"$ref":"#/components/schemas/Uuid"},"channelName":{"type":"string"},"kind":{"type":"string","enum":["door","pos","legacy","marketplace","venue","other"]},"seats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"referenceUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"releasedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","occurrenceId","channelId","channelName","kind","seats","label","externalRef","referenceUrl","note","createdAt","releasedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440071","businessId":"550e8400-e29b-41d4-a716-446655440000","occurrenceId":"550e8400-e29b-41d4-a716-446655440010:2026-09-01T17:00:00.000Z","channelId":"550e8400-e29b-41d4-a716-446655440070","channelName":"Square","kind":"pos","seats":2,"label":null,"externalRef":"sqr_123","referenceUrl":"https://squareup.com/dashboard/orders/overview/sqr_123","note":null,"createdAt":"2026-09-01T17:00:00.000Z","releasedAt":null}},"ChannelClaimWithWarnings":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"type":"string"},"channelId":{"$ref":"#/components/schemas/Uuid"},"channelName":{"type":"string"},"kind":{"type":"string","enum":["door","pos","legacy","marketplace","venue","other"]},"seats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"referenceUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"releasedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"string","enum":["reference_format"]}}},"required":["id","businessId","occurrenceId","channelId","channelName","kind","seats","label","externalRef","referenceUrl","note","createdAt","releasedAt","warnings"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440071","businessId":"550e8400-e29b-41d4-a716-446655440000","occurrenceId":"550e8400-e29b-41d4-a716-446655440010:2026-09-01T17:00:00.000Z","channelId":"550e8400-e29b-41d4-a716-446655440070","channelName":"Square","kind":"pos","seats":2,"label":null,"externalRef":"sqr_123","referenceUrl":null,"note":null,"createdAt":"2026-09-01T17:00:00.000Z","releasedAt":null,"warnings":[]}},"ClaimSyncResult":{"type":"object","properties":{"status":{"type":"string","enum":["created","updated","released","unchanged","moved","sold_out","session_ended","occurrence_not_found","invalid"]},"claim":{"anyOf":[{"$ref":"#/components/schemas/ChannelClaim"},{"type":"null"}]},"remaining":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"string","enum":["reference_format"]}}},"required":["status","claim","remaining","warnings"],"additionalProperties":false,"example":{"status":"created","claim":null,"remaining":6,"warnings":[]}},"ClaimSyncBatchResult":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"externalRef":{"type":"string"},"status":{"type":"string","enum":["created","updated","released","unchanged","moved","sold_out","session_ended","occurrence_not_found","invalid"]},"claimId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"remaining":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"warnings":{"type":"array","items":{"type":"string","enum":["reference_format"]}},"message":{"type":"string"}},"required":["externalRef","status","claimId","remaining","warnings"],"additionalProperties":false}}},"required":["results"],"additionalProperties":false,"example":{"results":[{"externalRef":"sqr_123","status":"created","claimId":"550e8400-e29b-41d4-a716-446655440071","remaining":6,"warnings":[]},{"externalRef":"sqr_124","status":"sold_out","claimId":null,"remaining":null,"warnings":[],"message":"Sold out"}]}},"ConnectAccountSession":{"type":"object","properties":{"clientSecret":{"type":"string","description":"Stripe Account Session client secret for embedded onboarding","example":"acs_example_client_secret"},"publishableKey":{"type":"string","description":"Stripe publishable key the client initializes Connect.js with","example":"pk_example"},"stripeAccountId":{"type":"string","description":"Connected account the embedded components target","example":"acct_example"}},"required":["clientSecret","publishableKey","stripeAccountId"],"additionalProperties":false,"example":{"clientSecret":"acs_example_client_secret","publishableKey":"pk_example","stripeAccountId":"acct_example"}},"ConnectStatus":{"type":"object","properties":{"state":{"type":"string","enum":["not_connected","onboarding","connected"],"description":"The three-state payments onboarding status"},"stripeAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"chargesEnabled":{"type":"boolean"},"payoutsEnabled":{"type":"boolean"},"detailsSubmitted":{"type":"boolean"},"requirementsCurrentlyDue":{"type":"array","items":{"type":"string"},"description":"Stripe requirements the studio still owes"},"disabledReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"onboardingStatus":{"type":"string"},"feeBps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Effective platform fee in basis points (business override ?? PLATFORM_FEE_BPS); Stripe processing fee is separate"},"feeMode":{"type":"string","enum":["absorb","split","pass"],"description":"Who bears the platform fee"},"feeCustomerPct":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Customer share percent when feeMode is split"},"feeModeImpact":{"type":"object","properties":{"sessions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"spaces":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"instructors":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["sessions","spaces","instructors"],"additionalProperties":false,"description":"Published listing counts for fee-mode save confirmation (\"changes displayed price of N classes…\")"},"availableBalance":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stripe available balance in business currency (minor units); null when unknown / not connected. Today's \"In Stripe\" line."},"pendingBalance":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stripe pending balance in business currency (minor units); null when unknown / not connected"},"balanceCurrency":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO currency for availableBalance / pendingBalance (uppercase), or null"},"statementDescriptor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Card statement descriptor customers see (Stripe settings); null when unknown / not set"},"payoutBank":{"anyOf":[{"type":"object","properties":{"bankName":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"type":"string"},"currency":{"type":"string"}},"required":["bankName","last4","currency"],"additionalProperties":false},{"type":"null"}],"description":"Default payout bank on the connected account; null when unknown / none on file"}},"required":["state","stripeAccountId","chargesEnabled","payoutsEnabled","detailsSubmitted","requirementsCurrentlyDue","disabledReason","onboardingStatus","feeBps","feeMode","feeCustomerPct","feeModeImpact","availableBalance","pendingBalance","balanceCurrency","statementDescriptor","payoutBank"],"additionalProperties":false,"example":{"state":"connected","stripeAccountId":"acct_example","chargesEnabled":true,"payoutsEnabled":true,"detailsSubmitted":true,"requirementsCurrentlyDue":[],"disabledReason":null,"onboardingStatus":"complete","feeBps":200,"feeMode":"absorb","feeCustomerPct":50,"feeModeImpact":{"classes":14,"sessions":3,"spaces":0},"availableBalance":124050,"pendingBalance":5000,"balanceCurrency":"USD","statementDescriptor":"MDHOLT.COM","payoutBank":{"bankName":"STRIPE TEST BANK","last4":"6789","currency":"USD"}}},"PaymentsStatus":{"type":"object","properties":{"provider":{"type":"string","enum":["stripe","trx"],"description":"The business's card provider"},"ready":{"type":"boolean","description":"Whether the business can take card payments now — Stripe: charges enabled; TRX: login verified"},"stripe":{"description":"The Stripe Connect status, when the provider is stripe","$ref":"#/components/schemas/ConnectStatus"},"trx":{"description":"The masked merchant record, when the provider is trx; null when none is stored yet","anyOf":[{"$ref":"#/components/schemas/TrxAccount"},{"type":"null"}]},"capabilities":{"type":"object","properties":{"feeMode":{"type":"boolean","description":"The business may choose who bears the platform fee — false on TRX, which has none (build-plan/200 D1). Passes and memberships sell on both providers (build-plan/265 D14)"}},"required":["feeMode"],"additionalProperties":false,"description":"What this business's payment account supports; the console hides what is false and every server door answers 409 not_available_on_provider"}},"required":["provider","ready","capabilities"],"additionalProperties":false,"example":{"provider":"stripe","ready":true,"stripe":{"state":"connected","stripeAccountId":"acct_example","chargesEnabled":true,"payoutsEnabled":true,"detailsSubmitted":true,"requirementsCurrentlyDue":[],"disabledReason":null,"onboardingStatus":"complete","feeBps":200,"feeMode":"absorb","feeCustomerPct":50,"feeModeImpact":{"classes":14,"sessions":3,"spaces":0},"availableBalance":124050,"pendingBalance":5000,"balanceCurrency":"USD","statementDescriptor":"MDHOLT.COM","payoutBank":{"bankName":"STRIPE TEST BANK","last4":"6789","currency":"USD"}},"capabilities":{"feeMode":true}}},"TrxAccount":{"type":"object","properties":{"merchantNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The processor merchant id (MID), shown whole"},"clientId":{"type":"string","description":"The TRX client id, shown whole"},"dba":{"anyOf":[{"type":"string"},{"type":"null"}]},"jsonUsernameLast4":{"type":"string","description":"The gateway JSON login as its last four, `••••0002`; never the whole login"},"storageSafeLast4":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The StorageSafe vault id as its last four, or null when none is stored"},"country":{"type":"string","description":"ISO 3166-1 alpha-2; TRX derives its currency code from it"},"currency":{"type":"string","enum":["USD","CAD"],"description":"The business's currency; TRX supports these two"},"environment":{"type":"string","enum":["test","live"],"description":"Which gateway the login belongs to, read off TRX_GATEWAY_URL"},"sharedWithLegacy":{"type":"boolean","description":"The legacy system still charges this merchant account: a batch then holds its volume beside ours, and settlement speaks for our part only"},"verifiedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When an authenticated Credit/Lookup last proved the login; a TRX business is ready to take cards exactly when set"},"verifyError":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why the last probe did not prove the login; null after a success"}},"required":["merchantNumber","clientId","dba","jsonUsernameLast4","storageSafeLast4","country","currency","environment","sharedWithLegacy","verifiedAt","verifyError"],"additionalProperties":false,"example":{"merchantNumber":"8788290000412","clientId":"412","dba":"Ash Street Yoga","jsonUsernameLast4":"••••0002","storageSafeLast4":"••••7A01","country":"US","currency":"USD","environment":"test","sharedWithLegacy":false,"verifiedAt":"2026-07-24T12:00:00.000Z","verifyError":null}},"DemoState":{"type":"object","properties":{"demoMode":{"type":"boolean","description":"Whether demo mode is on"},"available":{"type":"boolean","description":"Whether it can be switched on — always"},"live":{"type":"boolean","description":"Payments are live: while demo is on, real customers book for free too"},"counts":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Demo bookings — a series enrollment counts once"},"passes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Demo passes"},"customers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Customers the demo made who have nothing real on them"}},"required":["bookings","passes","customers"],"additionalProperties":false,"description":"What Clear, or ending demo, would delete now"}},"required":["demoMode","available","live","counts"],"additionalProperties":false,"example":{"demoMode":true,"available":true,"live":false,"counts":{"bookings":4,"passes":1,"customers":2}}},"DemoClearResult":{"type":"object","properties":{"demoMode":{"type":"boolean","description":"Whether demo mode is still on — false after ending it"},"deleted":{"type":"object","properties":{"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Demo bookings — a series enrollment counts once"},"passes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Demo passes"},"customers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Customers the demo made who have nothing real on them"}},"required":["bookings","passes","customers"],"additionalProperties":false,"description":"What was deleted"}},"required":["demoMode","deleted"],"additionalProperties":false,"example":{"demoMode":true,"deleted":{"bookings":4,"passes":1,"customers":2}}},"TrxApplication":{"type":"object","properties":{"enabled":{"type":"boolean","description":"TRX applications are open (TRX_ONBOARDING_ENABLED and the onboarding login set); false hides the choice"},"provider":{"type":"string","enum":["stripe","trx"],"description":"The business's payments provider"},"canChooseProvider":{"type":"boolean","description":"No card payment, no Stripe account and no TRX record yet: the provider may still be chosen or changed (a payment recorded by hand does not count)"},"status":{"type":"string","enum":["none","draft","documents_needed","in_review","approved","not_approved","live"],"description":"Apply (none, draft) → In review → Approved (Client; a platform admin finishes setup) → Live (the TRX record verified). documents_needed: TRX did not take a document; not_approved: TRX marked the lead Dead"},"draft":{"type":"object","properties":{"business":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"owners":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"bank":{"type":"object","properties":{"accountType":{"type":"string","enum":["checking","savings"]},"holder":{"type":"string","enum":["business","personal"]},"feesSameAccount":{"type":"boolean"}},"additionalProperties":false},"volumes":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["business","owners","bank","volumes"],"additionalProperties":false,"description":"The saved non-sensitive draft, else a prefill from the business, its first location and the signed-in owner"},"submittedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"leadState":{"anyOf":[{"type":"string","enum":["New","Working","Dead","Application","eSignature","Client"]},{"type":"null"}],"description":"TRX's LeadState as Lead/Lookup last answered it"},"clientNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"TRX's client number once the lead is a Client"},"documents":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["id_front","id_back","id2_front","id2_back","voided_check","bank_letter","w9","ss4","application"]},"state":{"type":"string","enum":["sent","failed"]},"at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["kind","state","at"],"additionalProperties":false}},"masked":{"anyOf":[{"type":"object","properties":{"owners":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"ssnLast4":{"type":"string"}},"required":["name","ssnLast4"],"additionalProperties":false}},"depositLast4":{"type":"string"},"feesLast4":{"type":"string"}},"additionalProperties":false},{"type":"null"}],"description":"Last fours only, once submitted"},"pricing":{"description":"The pricing the application states (page 2): the business’s own, else the default","$ref":"#/components/schemas/TrxPricing"},"timeZone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The studio's IANA zone — the signed application's dates are written in it"},"signature":{"anyOf":[{"type":"object","properties":{"signerName":{"type":"string"},"signedAt":{"type":"string"}},"required":["signerName","signedAt"],"additionalProperties":false},{"type":"null"}],"description":"Who signed the application and when (the server’s clock) — never the PDF"},"admin":{"description":"Platform admins only: TRX's references and the last lookup","type":"object","properties":{"leadGuid":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactGuids":{"type":"array","items":{"type":"string"}},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"fileType":{"type":"string"},"fileGuid":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["kind","fileType","fileGuid","error"],"additionalProperties":false}},"lookedUpAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lookupError":{"anyOf":[{"type":"string"},{"type":"null"}]},"submittedByPersonId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["leadGuid","contactGuids","files","lookedUpAt","lookupError","submittedByPersonId"],"additionalProperties":false}},"required":["enabled","provider","canChooseProvider","status","draft","submittedAt","leadState","clientNumber","documents","masked","pricing","timeZone","signature"],"additionalProperties":false,"example":{"enabled":true,"provider":"trx","canChooseProvider":true,"status":"in_review","draft":{"business":{"legalName":"Ash Street Yoga LLC","dba":"Ash Street Yoga","ownershipType":"LLC","city":"Portland","region":"OR"},"owners":[{"firstName":"Avery","lastName":"Example","ownershipPercent":"100","email":"avery@example.com"}],"bank":{"accountType":"checking","holder":"business","feesSameAccount":true},"volumes":{"monthlyVolume":"12000","dailyVolume":"1500","averageTicket":"25","maximumTicket":"400"}},"submittedAt":"2026-10-05T17:00:00.000Z","leadState":"New","clientNumber":null,"documents":[{"kind":"id_front","state":"sent","at":"2026-10-05T17:00:02.000Z"},{"kind":"voided_check","state":"sent","at":"2026-10-05T17:00:03.000Z"}],"masked":{"owners":[{"name":"Avery Example","ssnLast4":"1111"}],"depositLast4":"1111","feesLast4":"1111"},"pricing":{"model":"flat","rateBps":290,"perItemCents":30,"amexRateBps":null,"amexPerItemCents":null,"batchFeeCents":null,"chargebackFeeCents":null,"isDefault":true,"updatedAt":null},"timeZone":"America/Los_Angeles","signature":{"signerName":"Avery Example","signedAt":"2026-10-05T17:00:00.000Z"}}},"TrxPricing":{"type":"object","properties":{"model":{"type":"string","enum":["flat","interchange_plus"]},"rateBps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Flat: the discount rate; interchange plus: the markup. Basis points"},"perItemCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amexRateBps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Interchange plus: Amex’s markup; null = the same"},"amexPerItemCents":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"batchFeeCents":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"chargebackFeeCents":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"isDefault":{"type":"boolean","description":"No pricing set for the business: TRX_PRICING_DEFAULT_PERCENT / _PER_ITEM (flat 2.9% + 30¢)"},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["model","rateBps","perItemCents","amexRateBps","amexPerItemCents","batchFeeCents","chargebackFeeCents","isDefault","updatedAt"],"additionalProperties":false,"example":{"model":"flat","rateBps":290,"perItemCents":30,"amexRateBps":null,"amexPerItemCents":null,"batchFeeCents":null,"chargebackFeeCents":null,"isDefault":true,"updatedAt":null}},"LegacyTrxPull":{"type":"object","properties":{"state":{"type":"string","enum":["waiting","running","done","failed"],"description":"waiting until the worker takes it; failed is a run that threw (legacy unreachable)"},"legacyAccountRef":{"type":"string","description":"The legacy account as typed — its id, or the name in its PlaceFull links"},"requestedAt":{"type":"string"},"legacyAccount":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"condensedName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","condensedName"],"additionalProperties":false},{"type":"null"}],"description":"The legacy account the ref named, once found"},"outcome":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["no_bridge","no_account","brought","unchanged","not_trx","no_login","no_key","undecryptable","no_client","unsupported_country","currency_mismatch","kept_provider","failed"],"description":"brought wrote the record and ran the verify probe; unchanged found it already as legacy has it; every other status left the business as it was — no_bridge (the worker has no legacy connection), no_account (nothing in legacy answers to the ref), not_trx, no_login, no_key, undecryptable, no_client, unsupported_country, currency_mismatch, kept_provider (the business already has card payments on its provider), failed"},"provider":{"description":"The business's provider after the pull","type":"string","enum":["stripe","trx"]},"verified":{"description":"Whether the stored login is proved; null when no record is stored","anyOf":[{"type":"boolean"},{"type":"null"}]},"verifyError":{"anyOf":[{"type":"string"},{"type":"null"}]},"merchantNumber":{"description":"The MID, whole","anyOf":[{"type":"string"},{"type":"null"}]},"loginLast4":{"description":"The gateway login as its last four; never the login whole, never a password","anyOf":[{"type":"string"},{"type":"null"}]},"message":{"type":"string"}},"required":["status"],"additionalProperties":false},{"type":"null"}],"description":"What the run did; set once done"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why the run did not finish; set when failed"}},"required":["state","legacyAccountRef","requestedAt","legacyAccount","outcome","error"],"additionalProperties":false,"example":{"state":"done","legacyAccountRef":"ash-street-yoga","requestedAt":"2026-07-24T12:00:00.000Z","legacyAccount":{"id":"7A1C0DE0-1111-4222-8333-944455556666","name":"Ash Street Yoga","condensedName":"ash-street-yoga"},"outcome":{"status":"brought","provider":"trx","verified":true,"verifyError":null,"merchantNumber":"8788290000412","loginLast4":"••••0002"},"error":null}},"Payment":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"membershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"provider":{"type":"string","enum":["stripe","manual","trx"]},"providerRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"connectedAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"applicationFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"amount":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"purpose":{"type":"string","enum":["booking_deposit","booking_balance","booking_full","membership","open","cart"]},"status":{"type":"string","enum":["requires_action","authorized","captured","canceled","failed","refunded","partially_refunded"]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","customerId","bookingId","membershipId","cartId","provider","providerRef","connectedAccountId","applicationFeeAmount","amount","currency","purpose","status","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"PaymentActionResult":{"type":"object","properties":{"payment":{"$ref":"#/components/schemas/Payment"},"clientSecret":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["payment"],"additionalProperties":false,"example":{"payment":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"clientSecret":"pi_example_client_secret"}},"LedgerBalances":{"type":"object","properties":{"total":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"}},"required":["total","currency"],"additionalProperties":false,"example":{"total":12500,"currency":"USD"}},"CustomerListResult":{"type":"object","properties":{"customers":{"type":"array","items":{"$ref":"#/components/schemas/CustomerDetail"}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"filterCounts":{"type":"object","properties":{"all":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"subscribed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"hasAccount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"imported":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"archived":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"duplicates":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wallet":{"description":"Holding a Wallet pass a note reaches: a ticket for a class still to come or a studio card (build-plan/262).","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["all","subscribed","hasAccount","imported","archived","duplicates"],"additionalProperties":false}},"required":["customers","total","limit","offset","filterCounts"],"additionalProperties":false,"example":{"customers":[{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"noShowForecast":null,"guardian":null,"dependents":[]}],"total":1,"limit":25,"offset":0,"filterCounts":{"all":1,"subscribed":1,"hasAccount":1,"imported":0,"archived":0,"duplicates":0,"wallet":0}}},"CustomerDetail":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"personId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"contact":{"$ref":"#/components/schemas/CustomerContact"},"hasAccount":{"type":"boolean"},"guardianCustomerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"mergedIntoId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"linkedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"linkSource":{"anyOf":[{"type":"string","enum":["signin","checkout","waitlist","membership","backfill"]},{"type":"null"}]},"status":{"type":"string","enum":["active","archived"]},"source":{"type":"string","enum":["booking","import","manual"]},"tags":{"type":"array","items":{"type":"string"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"marketingConsent":{"type":"boolean"},"consentUpdatedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"consentSource":{"anyOf":[{"type":"string","enum":["checkout","preferences","unsubscribe","admin","import","merge"]},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"stats":{"$ref":"#/components/schemas/CustomerDerivedStats"},"noShowForecast":{"anyOf":[{"$ref":"#/components/schemas/CustomerNoShowForecast"},{"type":"null"}]},"guardian":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"dependents":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}},"memberships":{"description":"Every membership and pass this customer holds, live or not — present on the single-customer read (the customer record), absent on list rows and write responses.","type":"array","items":{"$ref":"#/components/schemas/MembershipDetail"}},"cardOnFile":{"description":"The customer's live card on file at this business (build-plan/265) — what the desk's Charge card on file bills. On the single-customer read; null with none.","anyOf":[{"type":"object","properties":{"brand":{"type":"string"},"last4":{"type":"string"},"label":{"type":"string"}},"required":["brand","last4","label"],"additionalProperties":false},{"type":"null"}]},"wallet":{"description":"Holding a Wallet pass a note reaches — a ticket for a class still to come or a studio card — in which wallets, since when (build-plan/262). On the single-customer read; null holds none.","anyOf":[{"type":"object","properties":{"apple":{"type":"boolean"},"google":{"type":"boolean"},"since":{"type":"string"}},"required":["apple","google","since"],"additionalProperties":false},{"type":"null"}]}},"required":["id","businessId","personId","contact","hasAccount","guardianCustomerId","mergedIntoId","linkedAt","linkSource","status","source","tags","notes","marketingConsent","consentUpdatedAt","consentSource","createdAt","updatedAt","archivedAt","stats","noShowForecast","guardian","dependents"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"noShowForecast":null,"guardian":null,"dependents":[]}},"CustomerContact":{"type":"object","properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"givenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"familyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["email","phone","givenName","familyName","displayName"],"additionalProperties":false,"example":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"}},"CustomerDerivedStats":{"type":"object","properties":{"firstSeenAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"lastSeenAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"lastBookingStartAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"nextBookingStartAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"bookingsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"canceledCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"noShowCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lifetimeSpendAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"lifetimeSpendCurrency":{"anyOf":[{"$ref":"#/components/schemas/Currency"},{"type":"null"}]},"activeMemberships":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["firstSeenAt","lastSeenAt","lastBookingStartAt","nextBookingStartAt","bookingsCount","canceledCount","noShowCount","lifetimeSpendAmount","lifetimeSpendCurrency","activeMemberships"],"additionalProperties":false,"example":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1}},"CustomerNoShowForecast":{"type":"object","properties":{"riskBps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"studioRateBps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"modelId":{"type":"string"},"computedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["riskBps","studioRateBps","modelId","computedAt"],"additionalProperties":false,"example":{"riskBps":1200,"studioRateBps":800,"modelId":"timesfm-2.5-200m","computedAt":"2026-09-07T12:00:00.000Z"}},"MembershipDetail":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"membershipPlanId":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["active","past_due","paused","canceled","expired"]},"startedAt":{"$ref":"#/components/schemas/Timestamp"},"currentPeriodEnd":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"paymentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"billingMode":{"type":"string","enum":["card","manual","none"]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"planName":{"type":"string"},"planBillingPeriod":{"type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"planHasCredits":{"type":"boolean"},"customerName":{"type":"string"},"customerEmail":{"anyOf":[{"type":"string"},{"type":"null"}]},"creditsRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cancelAtPeriodEnd":{"type":"boolean"},"pausedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"renewalAttempts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"periodNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"card":{"anyOf":[{"type":"object","properties":{"brand":{"type":"string"},"last4":{"type":"string"},"label":{"type":"string"}},"required":["brand","last4","label"],"additionalProperties":false},{"type":"null"}],"description":"The card on file it renews on (build-plan/265); null on a manual membership or a pass"},"lastPayment":{"anyOf":[{"type":"object","properties":{"at":{"$ref":"#/components/schemas/Timestamp"},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["paid","declined"]},"declineCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"declineMessage":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["at","amount","currency","status","declineCode","declineMessage"],"additionalProperties":false},{"type":"null"}],"description":"The last payment or decline — a Payment, or a period recorded at the desk"},"nextAttemptAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"When the card is tried next: the pending renewal, or a retry on a past-due membership"},"planPriceAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The period's price, for the Next charge column"},"planPriceCurrency":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","membershipPlanId","businessId","customerId","status","startedAt","currentPeriodEnd","paymentId","billingMode","createdAt","updatedAt","planName","planBillingPeriod","planHasCredits","customerName","customerEmail","creditsRemaining","card","lastPayment","nextAttemptAt","planPriceAmount","planPriceCurrency"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440011","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","paymentId":"550e8400-e29b-41d4-a716-446655440009","billingMode":"card","cardId":"550e8400-e29b-41d4-a716-446655440099","periodAnchorAt":"2026-07-24T12:00:00.000Z","periodNumber":1,"cancelAtPeriodEnd":false,"pausedAt":null,"renewalAttempts":0,"lastRenewalPaymentId":"550e8400-e29b-41d4-a716-446655440009","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","planName":"Unlimited Monthly","planBillingPeriod":"monthly","planHasCredits":false,"customerName":"Alex Rivera","customerEmail":"alex@example.com","creditsRemaining":8,"card":{"brand":"visa","last4":"4242","label":"Visa ···· 4242"},"lastPayment":{"at":"2026-07-24T12:00:00.000Z","amount":9000,"currency":"USD","status":"paid","declineCode":null,"declineMessage":null},"nextAttemptAt":"2026-08-01T18:00:00.000Z","planPriceAmount":9000,"planPriceCurrency":"USD"}},"CustomerImportResult":{"type":"object","properties":{"added":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"updated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"skipped":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the request rows"},"reason":{"type":"string"}},"required":["index","reason"],"additionalProperties":false}}},"required":["added","updated","unchanged","skipped"],"additionalProperties":false,"example":{"added":480,"updated":12,"unchanged":5,"skipped":[{"index":41,"reason":"Missing email and phone"}]}},"Customer":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"personId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"contact":{"$ref":"#/components/schemas/CustomerContact"},"hasAccount":{"type":"boolean"},"guardianCustomerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"mergedIntoId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"linkedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"linkSource":{"anyOf":[{"type":"string","enum":["signin","checkout","waitlist","membership","backfill"]},{"type":"null"}]},"status":{"type":"string","enum":["active","archived"]},"source":{"type":"string","enum":["booking","import","manual"]},"tags":{"type":"array","items":{"type":"string"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"marketingConsent":{"type":"boolean"},"consentUpdatedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"consentSource":{"anyOf":[{"type":"string","enum":["checkout","preferences","unsubscribe","admin","import","merge"]},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","personId","contact","hasAccount","guardianCustomerId","mergedIntoId","linkedAt","linkSource","status","source","tags","notes","marketingConsent","consentUpdatedAt","consentSource","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","personId":"550e8400-e29b-41d4-a716-446655440001","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"guardianCustomerId":null,"mergedIntoId":null,"linkedAt":"2026-07-24T12:00:00.000Z","linkSource":"checkout","status":"active","source":"booking","tags":["regular"],"notes":"Prefers front row","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"MembershipPlan":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"$ref":"#/components/schemas/Currency"},"billingPeriod":{"type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"expiresAfterDays":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]},"newCustomersOnly":{"type":"boolean"},"upsellAtCheckout":{"type":"boolean","description":"Offer at checkout — the checkout upsell (\"Add a 10-class pass … and this class is included\") considers only passes with this on (MDH-113). Default true."},"taxable":{"type":"boolean","description":"Sales tax applies at the rates in Settings. Default true; inert until the business holds rates (MDH-161)."},"revenueCategoryId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"What this is in the studio's books and which taxes it carries (architecture/31). With one, `taxable` is inert. Null = none."},"status":{"type":"string","enum":["draft","published","archived"]},"benefits":{"type":"array","items":{"$ref":"#/components/schemas/Benefit"}},"displayOrder":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Operator-controlled order within membership or pack family — build-plan/93."},"cardDesign":{"anyOf":[{"type":"object","properties":{"v":{"type":"number","const":1},"style":{"type":"string","enum":["modern","friendly","bold","calm","classic"]},"layout":{"type":"string","enum":["field","photo","split"]},"palette":{"type":"object","properties":{"ground":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"ink":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]},"accent":{"anyOf":[{"type":"object","properties":{"ref":{"type":"string","enum":["ground","ink","accent"]}},"required":["ref"],"additionalProperties":false},{"type":"object","properties":{"hex":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["hex"],"additionalProperties":false}]}},"required":["ground","ink","accent"],"additionalProperties":false},"surface":{"default":"plastic","type":"string","enum":["paper","plastic","metal"]},"pattern":{"type":"string","enum":["none","lines","dots","grid","arcs"]},"photo":{"anyOf":[{"type":"object","properties":{"treatment":{"type":"string","enum":["natural","duotone","soft"]},"focal":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["x","y"],"additionalProperties":false}},"required":["treatment","focal"],"additionalProperties":false},{"type":"null"}]},"logo":{"type":"string","enum":["auto","show","hide"]},"hand_set":{"type":"array","items":{"type":"string","enum":["style","layout","palette","surface","pattern","photo","logo"]}},"designed_by":{"type":"string","enum":["default","ai","owner"]},"rationale":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["v","style","layout","palette","surface","pattern","photo","logo","hand_set","designed_by","rationale"],"additionalProperties":false},{"type":"null"}],"description":"The plan's card design spec (architecture/27-cards.md § Spec) — null until designed. No kind, no price, no customer data. `hand_set` and `designed_by` are written by the server."},"cardImage":{"anyOf":[{"type":"object","properties":{"sm":{"type":"string","description":"The offer face, 160 px wide WebP — the console list thumbnail."},"md":{"type":"string","description":"The offer face, 640 px wide WebP."}},"required":["sm","md"],"additionalProperties":false},{"type":"null"}],"description":"Public URLs of the plan's offer face (architecture/27-cards.md § Surfaces), rendered on the first read and cached. Null when the plan has no card design (MDH-122)."},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","name","description","priceAmount","priceCurrency","billingPeriod","expiresAfterDays","newCustomersOnly","upsellAtCheckout","taxable","revenueCategoryId","status","benefits","displayOrder","cardDesign","cardImage","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Unlimited Monthly","description":"10% off all classes","priceAmount":9900,"priceCurrency":"USD","billingPeriod":"monthly","expiresAfterDays":null,"newCustomersOnly":false,"upsellAtCheckout":true,"taxable":true,"revenueCategoryId":null,"status":"published","benefits":[{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"cardDesign":{"v":1,"style":"modern","layout":"field","palette":{"ground":{"ref":"ground"},"ink":{"ref":"ink"},"accent":{"ref":"accent"}},"surface":"plastic","pattern":"none","photo":null,"logo":"auto","hand_set":[],"designed_by":"default","rationale":null},"cardImage":{"sm":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/4f1d9c2b7e60a8d3.webp","md":"https://assets.placefull.ai/550e8400-e29b-41d4-a716-446655440002/cards/a93e07c55b12f4e8.webp"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"Benefit":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"membershipPlanId":{"$ref":"#/components/schemas/Uuid"},"type":{"type":"string","enum":["access","price","credit"]},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","membershipPlanId","type","config","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440018","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","type":"price","config":{"mode":"percent","value":10,"scope":"all"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"PurchaseMembershipResult":{"type":"object","properties":{"paymentId":{"type":"string"},"membership":{"$ref":"#/components/schemas/Membership"},"creditsGranted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cartUrl":{"description":"With `provider: link`: the cart pay link for the plan — a recurring plan is bought through the cart like a pack, and the first period's charge saves the card it renews on (build-plan/265 D1). No membership until the cart is paid.","type":"string","format":"uri"},"cartToken":{"type":"string"}},"required":["paymentId","creditsGranted"],"additionalProperties":false,"example":{"paymentId":"550e8400-e29b-41d4-a716-446655440009","membership":{"id":"550e8400-e29b-41d4-a716-446655440011","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","paymentId":"550e8400-e29b-41d4-a716-446655440009","billingMode":"card","cardId":"550e8400-e29b-41d4-a716-446655440099","periodAnchorAt":"2026-07-24T12:00:00.000Z","periodNumber":1,"cancelAtPeriodEnd":false,"pausedAt":null,"renewalAttempts":0,"lastRenewalPaymentId":"550e8400-e29b-41d4-a716-446655440009","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"creditsGranted":10}},"Membership":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"membershipPlanId":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["active","past_due","paused","canceled","expired"]},"startedAt":{"$ref":"#/components/schemas/Timestamp"},"currentPeriodEnd":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"paymentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"billingMode":{"type":"string","enum":["card","manual","none"],"description":"`card`: renews on the card on file at each period end, the clock ours (build-plan/265). `manual`: periods recorded by the desk. `none`: a pass bought once."},"cardId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"The card on file a `card` membership renews on (architecture/05 § The card on file)"},"periodAnchorAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"The instant the periods count from — the first charge, moved forward by a pause (build-plan/265 D5)"},"periodNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Periods paid so far; the next renewal charges period + 1"},"cancelAtPeriodEnd":{"type":"boolean","description":"The holder or the desk asked to end at the period end; nothing more is charged (D7)"},"pausedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"renewalAttempts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Declines in the current renewal, 0 when paid; the ladder is 1, 3, 7 days then ended (D4)"},"lastRenewalPaymentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","membershipPlanId","businessId","customerId","status","startedAt","currentPeriodEnd","paymentId","billingMode","cardId","periodAnchorAt","periodNumber","cancelAtPeriodEnd","pausedAt","renewalAttempts","lastRenewalPaymentId","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440011","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","paymentId":"550e8400-e29b-41d4-a716-446655440009","billingMode":"card","cardId":"550e8400-e29b-41d4-a716-446655440099","periodAnchorAt":"2026-07-24T12:00:00.000Z","periodNumber":1,"cancelAtPeriodEnd":false,"pausedAt":null,"renewalAttempts":0,"lastRenewalPaymentId":"550e8400-e29b-41d4-a716-446655440009","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"MembershipListResult":{"type":"object","properties":{"memberships":{"type":"array","items":{"$ref":"#/components/schemas/MembershipDetail"}}},"required":["memberships"],"additionalProperties":false,"example":{"memberships":[{"id":"550e8400-e29b-41d4-a716-446655440011","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","paymentId":"550e8400-e29b-41d4-a716-446655440009","billingMode":"card","cardId":"550e8400-e29b-41d4-a716-446655440099","periodAnchorAt":"2026-07-24T12:00:00.000Z","periodNumber":1,"cancelAtPeriodEnd":false,"pausedAt":null,"renewalAttempts":0,"lastRenewalPaymentId":"550e8400-e29b-41d4-a716-446655440009","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","planName":"Unlimited Monthly","planBillingPeriod":"monthly","planHasCredits":false,"customerName":"Alex Rivera","customerEmail":"alex@example.com","creditsRemaining":8,"card":{"brand":"visa","last4":"4242","label":"Visa ···· 4242"},"lastPayment":{"at":"2026-07-24T12:00:00.000Z","amount":9000,"currency":"USD","status":"paid","declineCode":null,"declineMessage":null},"nextAttemptAt":"2026-08-01T18:00:00.000Z","planPriceAmount":9000,"planPriceCurrency":"USD"}]}},"MembershipRenewalOutcome":{"type":"object","properties":{"outcome":{"type":"string","enum":["nothing","early","canceled","settled_free","charged","declined","pending"],"description":"`charged`: the period is paid and the membership active; `declined`: the card said no, `nextAttemptAt` is the next try or null when the membership ended; `pending`: the processor has not answered yet; `settled_free`: a $0 period advanced; `early`: the period has not ended; `canceled`: the cancel at period end took effect; `nothing`: not a card membership, paused, or ended."},"reason":{"type":"string","enum":["not_found","ended","not_card","paused"]},"paymentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"periodNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currentPeriodEnd":{"$ref":"#/components/schemas/Timestamp"},"dueAt":{"$ref":"#/components/schemas/Timestamp"},"endedAt":{"$ref":"#/components/schemas/Timestamp"},"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"nextAttemptAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"nextAskAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"ended":{"type":"boolean"},"decline":{"type":"object","properties":{"code":{"anyOf":[{"type":"string"},{"type":"null"}]},"declineCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"message":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["code","declineCode","message"],"additionalProperties":{}}},"required":["outcome"],"additionalProperties":false,"example":{"outcome":"charged","paymentId":"550e8400-e29b-41d4-a716-446655440009","amount":9000,"currency":"USD","periodNumber":2,"currentPeriodEnd":"2026-08-01T18:00:00.000Z"}},"SpotsChangeQuote":{"type":"object","properties":{"membershipId":{"$ref":"#/components/schemas/Uuid"},"currency":{"type":"string"},"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"What the subscription holds now."},"scheduledSpots":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"A removal already waiting for the term's end."},"to":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The count asked for."},"direction":{"type":"string","enum":["add","remove","keep","same"],"description":"`add`: more spots from now, charged for the sessions left in the term; `remove`: fewer from the term's end, no refund; `keep`: a waiting removal taken back; `same`: nothing to do."},"min":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"max":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"term":{"type":"string","enum":["weekly","monthly"]},"pricePerSpot":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"nextChargeAt":{"type":"string","description":"The term's end: the next charge, and when a removal takes effect."},"nextTermAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Each term from the next charge at the new count, with today's discount, before tax."},"nextChargeAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The same with tax — the next charge."},"discount":{"anyOf":[{"type":"object","properties":{"discountId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"label":{"type":"string"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["discountId","label","amount"],"additionalProperties":false},{"type":"null"}]},"chargeNow":{"anyOf":[{"type":"object","properties":{"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"base":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"taxAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sessionsLeft":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sessionsInTerm":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["amount","base","taxAmount","sessionsLeft","sessionsInTerm"],"additionalProperties":false},{"type":"null"}],"description":"An add: the charge now, prorated by the sessions left in the term (two of four left is half)."},"effectiveAt":{"type":"string"},"blocked":{"anyOf":[{"type":"object","properties":{"occurrenceId":{"type":"string"},"startsAt":{"type":"string"},"label":{"type":"string"}},"required":["occurrenceId","startsAt","label"],"additionalProperties":false},{"type":"null"}],"description":"An add a session cannot take: the first such session. The change is refused."},"lines":{"type":"array","items":{"type":"string"},"description":"The sentences the sheet, the desk and the email say."},"action":{"type":"string","description":"The button: *Pay $52.50*, *Confirm* or *Done*."}},"required":["membershipId","currency","spots","scheduledSpots","to","direction","min","max","term","pricePerSpot","nextChargeAt","nextTermAmount","nextChargeAmount","discount","chargeNow","effectiveAt","blocked","lines","action"],"additionalProperties":false,"example":{"membershipId":"550e8400-e29b-41d4-a716-446655440080","currency":"USD","spots":2,"scheduledSpots":null,"to":3,"direction":"add","min":1,"max":6,"term":"monthly","pricePerSpot":8000,"nextChargeAt":"2026-11-13T15:00:00.000Z","nextTermAmount":20000,"nextChargeAmount":20000,"discount":{"discountId":"550e8400-e29b-41d4-a716-446655440081","label":"Siblings: half price after the first","amount":8000},"chargeNow":{"amount":2000,"base":2000,"taxAmount":0,"sessionsLeft":2,"sessionsInTerm":4},"effectiveAt":"2026-10-16T17:00:00.000Z","blocked":null,"lines":["3 spots from today.","$20.00 now for the 2 sessions left this month.","Siblings: half price after the first −$80.00 each month.","Then $200.00 every month from Nov 13."],"action":"Pay $20.00"}},"SpotsChangeResult":{"type":"object","properties":{"outcome":{"type":"string","enum":["added","scheduled","kept","unchanged","pending"]},"quote":{"$ref":"#/components/schemas/SpotsChangeQuote"},"paymentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["outcome","quote","paymentId"],"additionalProperties":false,"example":{"outcome":"added","quote":{"membershipId":"550e8400-e29b-41d4-a716-446655440080","currency":"USD","spots":2,"scheduledSpots":null,"to":3,"direction":"add","min":1,"max":6,"term":"monthly","pricePerSpot":8000,"nextChargeAt":"2026-11-13T15:00:00.000Z","nextTermAmount":20000,"nextChargeAmount":20000,"discount":{"discountId":"550e8400-e29b-41d4-a716-446655440081","label":"Siblings: half price after the first","amount":8000},"chargeNow":{"amount":2000,"base":2000,"taxAmount":0,"sessionsLeft":2,"sessionsInTerm":4},"effectiveAt":"2026-10-16T17:00:00.000Z","blocked":null,"lines":["3 spots from today.","$20.00 now for the 2 sessions left this month.","Siblings: half price after the first −$80.00 each month.","Then $200.00 every month from Nov 13."],"action":"Pay $20.00"},"paymentId":"550e8400-e29b-41d4-a716-446655440082"}},"MembershipCardLinkResult":{"type":"object","properties":{"scheduled":{"type":"boolean","const":true,"description":"The update-card email is booked for the holder"}},"required":["scheduled"],"additionalProperties":false,"example":{"scheduled":true}},"AccessCheckResult":{"type":"object","properties":{"allowed":{"type":"boolean"},"requiredKeys":{"type":"array","items":{"type":"string"}},"grantedKeys":{"type":"array","items":{"type":"string"}},"missingKeys":{"type":"array","items":{"type":"string"}}},"required":["allowed","requiredKeys","grantedKeys","missingKeys"],"additionalProperties":false,"example":{"allowed":true,"requiredKeys":["premium"],"grantedKeys":["premium"],"missingKeys":[]}},"TaxRate":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"type":"string"},"ratePpm":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","locationId","name","ratePpm","registrationNumber","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"name":"HST","ratePpm":130000,"registrationNumber":"123456789RT0001","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"TaxSetup":{"type":"object","properties":{"locations":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"jurisdictionLabel":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","region","jurisdictionLabel"],"additionalProperties":false}},"rates":{"type":"array","items":{"$ref":"#/components/schemas/TaxRate"}},"proposal":{"type":"object","properties":{"kind":{"type":"string","enum":["missing","canada","us"]},"message":{"anyOf":[{"type":"string"},{"type":"null"}]},"seededRates":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"ratePpm":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["name","ratePpm","locationId"],"additionalProperties":false}}},"required":["kind","message","seededRates"],"additionalProperties":false}},"required":["locations","rates","proposal"],"additionalProperties":false,"example":{"locations":[{"id":"550e8400-e29b-41d4-a716-446655440003","name":"Main","country":"CA","region":"ON","jurisdictionLabel":"Ontario, Canada"}],"rates":[{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"name":"HST","ratePpm":130000,"registrationNumber":"123456789RT0001","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"proposal":{"kind":"canada","message":null,"seededRates":[{"name":"HST","ratePpm":130000,"locationId":null}]}}},"RevenueCategory":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string","description":"Customer-visible: it prints on the receipt when a price is split across categories (architecture/31)."},"taxMode":{"type":"string","enum":["all","none","some"],"description":"all = every tax the line's location collects · none = no tax · some = the taxes named in taxNames."},"taxNames":{"type":"array","items":{"type":"string"},"description":"Tax names (not rate ids — a category is per business, rates are per location). Empty unless taxMode is some."},"taxSummary":{"type":"string","description":"Its taxes in words: \"Sales tax\", \"No tax\", \"GST, PST\"."},"usedBy":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Live listings, products and plans assigned to it. Archiving is refused while above zero."},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","name","taxMode","taxNames","taxSummary","usedBy","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440031","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Materials","taxMode":"all","taxNames":[],"taxSummary":"Sales tax","usedBy":2,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"CustomerList":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"rule":{"type":"object","properties":{"tag":{"description":"One tag on customer.tags.","type":"string"},"lastSeen":{"type":"object","properties":{"op":{"type":"string","enum":["within","more_than","never"]},"days":{"description":"Required for within / more_than.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["op"],"additionalProperties":false},"bookings":{"type":"string","enum":["none","1+","3+","10+"]},"holdsPass":{"type":"boolean"},"hasUpcoming":{"type":"boolean"},"source":{"type":"string","enum":["booking","import","manual"]},"wallet":{"description":"Holds a Wallet pass a note reaches (a ticket for a class still to come, or a studio card).","type":"boolean"}},"additionalProperties":false,"description":"Seven optional facts, all ANDed (architecture/32). Consent is never a fact — it is the floor of every send."},"ruleSentence":{"type":"string","description":"One-line readback — \"Last seen more than 90 days ago · 3 or more bookings\"."},"customers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Live customers matching the rule."},"subscribed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Subset that clears the consent floor (may be emailed). Always ≤ customers."},"wallet":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Subset holding a Wallet pass a note reaches. Always ≤ customers."},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","name","rule","ruleSentence","customers","subscribed","wallet","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440032","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Lapsed 90 days","rule":{"lastSeen":{"op":"more_than","days":90},"bookings":"3+"},"ruleSentence":"Last seen more than 90 days ago · 3 or more bookings","customers":84,"subscribed":61,"wallet":12,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"CustomerListCounts":{"type":"object","properties":{"customers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"subscribed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"wallet":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["customers","subscribed","wallet"],"additionalProperties":false,"example":{"customers":84,"subscribed":61,"wallet":12}},"Message":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"customerListId":{"$ref":"#/components/schemas/Uuid"},"customerListName":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"},"subject":{"type":"string"},"previewText":{"anyOf":[{"type":"string"},{"type":"null"}]},"bodyMd":{"type":"string"},"buttonLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"buttonUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","scheduled","sending","sent"]},"scheduledAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"sendStartedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"sentAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"canceledAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"recipientCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"wallet":{"type":"boolean","description":"Also notify the Wallet passes of the people in the group (build-plan/263)."},"walletCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People reached through a Wallet pass, frozen at fan-out."},"deliveredCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"openedCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"clickedCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"clonedFromId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"createdByUserId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","locationId","customerListId","customerListName","name","subject","previewText","bodyMd","buttonLabel","buttonUrl","status","scheduledAt","sendStartedAt","sentAt","canceledAt","archivedAt","recipientCount","wallet","walletCount","deliveredCount","openedCount","clickedCount","clonedFromId","createdByUserId","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440033","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","customerListId":"550e8400-e29b-41d4-a716-446655440032","customerListName":"Lapsed 90 days","name":"Fall schedule is live","subject":"The fall schedule is up","previewText":"Nine new classes.","bodyMd":"Booking is open now.","buttonLabel":"See the schedule","buttonUrl":"https://example.test/classes","status":"draft","scheduledAt":null,"sendStartedAt":null,"sentAt":null,"canceledAt":null,"archivedAt":null,"recipientCount":null,"wallet":false,"walletCount":null,"deliveredCount":null,"openedCount":null,"clickedCount":null,"clonedFromId":null,"createdByUserId":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"Discount":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"code":{"anyOf":[{"type":"string"},{"type":"null"}]},"appliesTo":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","const":"all"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"category"},"category":{"type":"string","enum":["class","session","space","product"]}},"required":["kind","category"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"listing"},"listingId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","listingId"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"product"},"productId":{"$ref":"#/components/schemas/Uuid"}},"required":["kind","productId"],"additionalProperties":false}]}},"effect":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","const":"percent"},"value":{"type":"integer","minimum":1,"maximum":100}},"required":["mode","value"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"amount"},"value":{"type":"integer","minimum":1,"maximum":9007199254740991},"per":{"type":"string","enum":["unit","order"]}},"required":["mode","value","per"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"price"},"value":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["mode","value"],"additionalProperties":false}]},"every":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"gets":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"afterFirst":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"when":{"anyOf":[{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},"start":{"anyOf":[{"type":"string"},{"type":"null"}]},"end":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["days","start","end"],"additionalProperties":false},{"type":"null"}]},"minQuantity":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"minAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"startsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"endsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"maxUses":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"uses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["active","paused"]},"promote":{"type":"boolean"},"description":{"type":"string"},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","name","code","appliesTo","effect","every","gets","afterFirst","when","minQuantity","minAmount","startsOn","endsOn","maxUses","uses","status","promote","description","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440030","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Saturday: $4 for 3+","code":null,"appliesTo":[{"kind":"listing","listingId":"550e8400-e29b-41d4-a716-446655440004"}],"effect":{"mode":"price","value":400},"every":1,"gets":1,"afterFirst":0,"when":{"days":[6],"start":null,"end":null},"minQuantity":3,"minAmount":null,"startsOn":null,"endsOn":null,"maxUses":null,"uses":0,"status":"active","promote":true,"description":"Saturdays: $4.00 a spot for Studio fee, 3 spots or more","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"AppConfig":{"type":"object","properties":{"productName":{"type":"string"},"appEnv":{"type":"string"},"appBaseUrl":{"type":"string"},"markEnv":{"anyOf":[{"type":"string"},{"type":"null"}]},"currencies":{"type":"array","items":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/CurrencyCode"},"name":{"type":"string"},"minorUnitDigits":{"anyOf":[{"type":"number","const":0},{"type":"number","const":2},{"type":"number","const":3}]}},"required":["code","name","minorUnitDigits"],"additionalProperties":false}},"dateFormats":{"type":"array","items":{"$ref":"#/components/schemas/DateFormat"}},"businessTypes":{"type":"array","items":{"type":"object","properties":{"value":{"$ref":"#/components/schemas/BusinessType"},"label":{"type":"string"},"hint":{"type":"string"}},"required":["value","label","hint"],"additionalProperties":false}},"productModules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"primer":{"type":"string"},"locked":{"type":"boolean"}},"required":["key","label","primer","locked"],"additionalProperties":false}},"access":{"type":"object","properties":{"roles":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["owner","manager","employee","instructor"]},"label":{"type":"string"},"line":{"type":"string"}},"required":["key","label","line"],"additionalProperties":false}},"buckets":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"keys":{"type":"array","items":{"type":"string"}},"label":{"type":"string"},"detail":{"type":"string"},"short":{"type":"string"}},"required":["key","keys","label","short"],"additionalProperties":false}},"bundles":{"type":"object","properties":{"owner":{"type":"array","items":{"type":"string"}},"manager":{"type":"array","items":{"type":"string"}},"employee":{"type":"array","items":{"type":"string"}},"instructor":{"type":"array","items":{"type":"string"}}},"required":["owner","manager","employee","instructor"],"additionalProperties":false}},"required":["roles","buckets","bundles"],"additionalProperties":false,"description":"Team › Access (build-plan/256): the four roles with their one line, the twelve rows Adjust shows (a lead key plus the keys it confers), and each role’s bundle of feature keys. A row is on when every key is in the bundle or granted and none is revoked."}},"required":["productName","appEnv","markEnv","currencies","dateFormats","businessTypes","productModules","access"],"additionalProperties":false,"example":{"productName":"PlaceFull","appEnv":"production","markEnv":null,"currencies":[{"code":"USD","name":"US dollar","minorUnitDigits":2},{"code":"GBP","name":"British pound","minorUnitDigits":2},{"code":"JPY","name":"Japanese yen","minorUnitDigits":0}],"dateFormats":["MDY","DMY","YMD"],"businessTypes":[{"value":"fitness_movement","label":"Fitness & movement","hint":"yoga, pilates, barre, dance, gym"},{"value":"art_maker","label":"Art & maker","hint":"pottery, painting, woodworking, craft"}],"productModules":[{"key":"classes","label":"Classes","primer":"Scheduled group classes customers book by the spot.","locked":false},{"key":"instructors","label":"Instructors","primer":"Name the people who teach and assign them to classes.","locked":false},{"key":"sessions","label":"Reservations","primer":"Private time with a person — lessons, readings, consults.","locked":false},{"key":"spaces","label":"Spaces","primer":"Rooms, equipment, and hourly rentals your business uses.","locked":false}],"access":{"roles":[{"key":"owner","label":"Owner","line":"Everything."},{"key":"manager","label":"Manager","line":"Everything but Settings and refunds."},{"key":"employee","label":"Front desk","line":"Takes bookings, checks people in, looks up and edits customers."},{"key":"instructor","label":"Teaches only","line":"Their own classes: rosters, check-in, messages."}],"buckets":[{"key":"booking.refund","keys":["booking.refund"],"label":"Refunds","detail":"Give money back on a payment.","short":"Refunds"},{"key":"reports.view","keys":["reports.view"],"label":"Performance","short":"Performance"}],"bundles":{"owner":["booking.view","booking.manage","booking.refund","reports.view"],"manager":["booking.view","booking.manage","reports.view"],"employee":["booking.view","booking.manage"],"instructor":["booking.view","booking.checkin"]}}}},"MeContext":{"type":"object","properties":{"person":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"email":{"$ref":"#/components/schemas/Email"},"legalGivenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalFamilyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","email","legalGivenName","legalFamilyName","displayName"],"additionalProperties":false},"businesses":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"currency":{"$ref":"#/components/schemas/CurrencyCode"},"locale":{"$ref":"#/components/schemas/Locale"},"dateFormat":{"$ref":"#/components/schemas/DateFormat"},"stripeOnboardingStatus":{"$ref":"#/components/schemas/StripeOnboardingStatus"},"paymentsProvider":{"type":"string","enum":["stripe","trx"]},"paymentsReady":{"type":"boolean","description":"The business can take cards now, whatever its provider. Until it can, the console's Payments page is where Stripe or TRX is set up."},"deskPaymentMethods":{"type":"array","items":{"type":"string","enum":["card","link","cash"]}},"paidElsewhere":{"type":"boolean"},"bookingMessages":{"type":"string","enum":["email","sms"]},"smsAvailable":{"type":"boolean"},"demoMode":{"type":"boolean"},"businessType":{"anyOf":[{"$ref":"#/components/schemas/BusinessType"},{"type":"null"}]},"roles":{"type":"array","items":{"type":"string"}},"enabledModules":{"type":"array","items":{"type":"string","enum":["classes","sessions","spaces","memberships","products"]}},"publishedModules":{"type":"array","items":{"type":"string","enum":["classes","sessions","spaces","memberships","products"]}},"modulesSelected":{"type":"boolean"},"locations":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"timezone":{"type":"string"},"logoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Location logo URL (md variant) — the scope menu tile"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO country — the desk address question uses it."}},"required":["id","name","slug","timezone","logoUrl","country"],"additionalProperties":false}},"merchantAgreement":{"type":"object","properties":{"stale":{"type":"boolean","description":"No acceptance counts — bookings are refused until an owner accepts."},"updateOffered":{"type":"boolean","description":"A newer version is offered for acceptance; the prior acceptance still counts."},"currentVersion":{"type":"string"},"currentSummary":{"type":"string"},"currentEffectiveAt":{"type":"string"},"acceptedVersion":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["stale","updateOffered","currentVersion","currentSummary","currentEffectiveAt","acceptedVersion"],"additionalProperties":false}},"required":["id","name","currency","locale","dateFormat","stripeOnboardingStatus","paymentsProvider","paymentsReady","deskPaymentMethods","paidElsewhere","bookingMessages","smsAvailable","demoMode","businessType","roles","enabledModules","publishedModules","modulesSelected","locations","merchantAgreement"],"additionalProperties":false}},"customerBusinessCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"upcomingBookingCount":{"type":"integer","minimum":0,"maximum":9007199254740991},"terminal":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"locationId":{"$ref":"#/components/schemas/Uuid"}},"required":["id","name","locationId"],"additionalProperties":false},{"type":"null"}],"description":"Set when the session was opened by a PIN on a paired terminal: `businesses` is then the terminal’s one business, capped at Front desk."},"platformAdmin":{"type":"boolean","description":"The caller is a platform admin: `businesses` is then every live business on the platform, each with every feature, and the console shows All locations."}},"required":["person","businesses","customerBusinessCount","upcomingBookingCount","terminal","platformAdmin"],"additionalProperties":false,"example":{"person":{"id":"550e8400-e29b-41d4-a716-446655440001","email":"ada@sunrise.example.com","legalGivenName":"Ada","legalFamilyName":"Potter","displayName":"Ada"},"businesses":[{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","currency":"USD","locale":"en-US","dateFormat":"MDY","stripeOnboardingStatus":"complete","paymentsProvider":"stripe","paymentsReady":true,"deskPaymentMethods":["card","link","cash"],"paidElsewhere":false,"bookingMessages":"email","smsAvailable":false,"demoMode":false,"businessType":"fitness_movement","roles":["owner"],"enabledModules":["classes","instructors","spaces","memberships"],"publishedModules":["classes","spaces"],"modulesSelected":true,"locations":[{"id":"550e8400-e29b-41d4-a716-446655440003","name":"Downtown Studio","slug":"sunrise-studio","timezone":"America/Denver","logoUrl":"https://cdn.example/sunrise/logo/md.webp","country":"US"}],"merchantAgreement":{"stale":false,"updateOffered":false,"currentVersion":"2026-08-30","currentSummary":"PlaceFull Acquisition Inc merchant agreement — location-based fee, marketing, Colorado law.","currentEffectiveAt":"2026-08-30T00:00:00.000Z","acceptedVersion":"2026-08-30"}}],"customerBusinessCount":1,"upcomingBookingCount":2,"terminal":null,"platformAdmin":false}},"ChangesMarker":{"type":"object","properties":{"marker":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["marker"],"additionalProperties":false},"HomeSummary":{"type":"object","properties":{"timezone":{"type":"string"},"day":{"type":"string"},"calendar":{"$ref":"#/components/schemas/OpsCalendarSummary"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/HomeMessageItem"}},"needsYou":{"type":"array","items":{"$ref":"#/components/schemas/HomeNeedsYouItem"}}},"required":["timezone","day","calendar","messages","needsYou"],"additionalProperties":false},"OpsCalendarSummary":{"type":"object","properties":{"timezone":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"hours":{"type":"array","items":{"type":"object","properties":{"startsAt":{"type":"string"},"endsAt":{"type":"string"},"localStart":{"type":"string"},"localEnd":{"type":"string"}},"required":["startsAt","endsAt","localStart","localEnd"],"additionalProperties":false}},"spaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}},"events":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["class","rental","session","block"]},"id":{"type":"string"},"title":{"type":"string"},"localStart":{"type":"string"},"localEnd":{"type":"string"},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"allDay":{"type":"boolean"},"offeringId":{"anyOf":[{"type":"string"},{"type":"null"}]},"occurrenceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringColor":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringIcon":{"anyOf":[{"type":"string","enum":["artboard","glass-full","wheel","hands","mug","brush","glass","flame","pencil","cookie","palette","door","moon","heart","users","kid","senior","tent","series","tools","cake","lock","team","school","fundraiser","tree","pumpkin","leaf","hearts","egg","flower","tie","star","confetti","skull","sun","ticket","gift-card","building","cash","beach","graduation-cap","dumbbell","kettlebell","biceps","person-standing","heart-pulse","timer","zap","bike","footprints","waves","user","baby","paintbrush","amphora","hand","scissors","sparkles","music","mic","camera","utensils","coffee","book"]},{"type":"null"}]},"offeringStatus":{"anyOf":[{"type":"string","enum":["draft","published","hidden","archived"]},{"type":"null"}]},"pieces":{"type":"boolean","description":"The listing has Pieces on — Today offers Log pieces while such a session runs (build-plan/283). False on blocked time."},"capacityTotal":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"capacityBooked":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"capacityRemaining":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"capacityByStatus":{"anyOf":[{"$ref":"#/components/schemas/ScheduleCapacityByStatus"},{"type":"null"}]},"instructors":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleClassInstructor"}},"instructorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"spaceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"spaceName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"parties":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"seats":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"checkedIn":{"type":"boolean"},"claimId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"channelName":{"type":"string"},"ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"owes":{"description":"Minor units still due on the booking.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"online":{"description":"The customer booked it online; false when the team added it.","type":"boolean"},"addedBy":{"description":"Who on the team booked it.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","seats","checkedIn"],"additionalProperties":false}},"checkedIn":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"waiting":{"description":"People on a class date's waitlist.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"listingImageUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["scheduled","canceled"]},"series":{"anyOf":[{"type":"object","properties":{"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["index","count"],"additionalProperties":false},{"type":"null"}]},"stranded":{"$ref":"#/components/schemas/StrandedReason"},"soloTeam":{"type":"boolean"}},"required":["kind","id","title","localStart","localEnd","startsAt","endsAt","allDay","offeringId","occurrenceId","offeringColor","offeringStatus","pieces","capacityTotal","capacityBooked","capacityRemaining","capacityByStatus","instructors","instructorName","spaceId","spaceName","customerName","parties","checkedIn","listingImageUrl","status","series","stranded","soloTeam"],"additionalProperties":false}}},"required":["timezone","from","to","hours","spaces","events"],"additionalProperties":false},"ScheduleClassInstructor":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"headshotUrl":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","headshotUrl"],"additionalProperties":false},"HomeMessageItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"status":{"type":"string","enum":["scheduled","sending","sent"]},"scheduledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"sentAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"recipientCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"deliveredCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"openedCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"clickedCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["id","name","status","scheduledAt","sentAt","recipientCount","deliveredCount","openedCount","clickedCount"],"additionalProperties":false},"HomeNeedsYouItem":{"type":"object","properties":{"kind":{"type":"string","enum":["balance_due","step_problem","task_failed","membership_past_due","confirmation_email_failed","accounting_post_failed","pickup_waiting","low_stock","stock_owed","social_reconnect","social_post_failed"]},"bookingId":{"type":"string"},"offeringId":{"type":"string"},"offeringName":{"type":"string"},"customerName":{"type":"string"},"occurrenceStartsAt":{"type":"string"},"localStart":{"type":"string"},"amountDue":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"taskType":{"type":"string"},"taskId":{"type":"string"},"membershipId":{"type":"string"},"planName":{"type":"string"},"failureDetail":{"anyOf":[{"type":"string"},{"type":"null"}]},"orderLineId":{"type":"string"},"customerId":{"type":"string"},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidAt":{"type":"string"},"key":{"type":"string","description":"Stable while the facts hold; a dismissal is kept by it."},"bookingStepId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"stepName":{"type":"string"},"stepAction":{"type":"string"},"problem":{"description":"A step's problem in the desk's words, and its one fix.","type":"object","properties":{"reason":{"type":"string","enum":["no_contact","texts_unavailable","phone_unreachable","send_failed","card_declined","not_checked_in","still_here"]},"text":{"type":"string"},"fix":{"type":"object","properties":{"kind":{"type":"string","enum":["open_customer","run_step","send_pay_link","open_booking"]},"verb":{"type":"string"}},"required":["kind","verb"],"additionalProperties":false}},"required":["reason","text","fix"],"additionalProperties":false}},"required":["kind","key"],"additionalProperties":false},"HomeActivityPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/HomeActivityItem"}},"seenAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"next":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["items","seenAt","next"],"additionalProperties":false},"HomeActivityItem":{"anyOf":[{"$ref":"#/components/schemas/HomeActivityBookingItem"},{"$ref":"#/components/schemas/HomeActivityPostedItem"}]},"HomeActivityBookingItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"at":{"type":"string"},"kind":{"type":"string","enum":["booked","cancelled","moved","spots"]},"online":{"type":"boolean","description":"The customer booked it online; false when the team added it."},"by":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Who on the team did it; null for a customer or the system."},"bookingId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"customerName":{"type":"string"},"listingName":{"type":"string"},"listingType":{"type":"string","enum":["class","session","space"]},"exclusive":{"type":"boolean"},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The booking's total, minor units."},"currency":{"type":"string"},"occurrenceId":{"type":"string"},"startsAt":{"type":"string"},"localStart":{"type":"string"},"previousLocalStart":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","at","kind","online","by","bookingId","customerName","listingName","listingType","exclusive","partySize","amount","currency","occurrenceId","startsAt","localStart","previousLocalStart"],"additionalProperties":false},"HomeActivityPostedItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"at":{"type":"string"},"kind":{"type":"string","const":"posted"},"socialPostId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"networks":{"type":"array","items":{"type":"string","enum":["instagram","facebook"]}},"title":{"type":"string"},"line":{"type":"string"}},"required":["id","at","kind","socialPostId","networks","title","line"],"additionalProperties":false},"HomeActivitySeen":{"type":"object","properties":{"seenAt":{"type":"string"}},"required":["seenAt"],"additionalProperties":false},"NeedsYouDismissed":{"type":"object","properties":{"dismissed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["dismissed"],"additionalProperties":false},"LocationReadiness":{"type":"object","properties":{"bookable":{"type":"boolean"},"ready":{"type":"boolean"},"bookingPaused":{"type":"boolean"},"chargesEnabled":{"type":"boolean"},"firstBookingAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["class","agreement","team"]},"state":{"type":"string","enum":["done","now","later"]},"blocking":{"type":"boolean"},"focusId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"focusType":{"anyOf":[{"type":"string","enum":["class","session","space"]},{"type":"null"}]}},"required":["id","state","blocking","focusId","focusType"],"additionalProperties":false}}},"required":["bookable","ready","bookingPaused","chargesEnabled","firstBookingAt","steps"],"additionalProperties":false},"OccupancyNow":{"type":"object","properties":{"location":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"timezone":{"type":"string"}},"required":["id","name","timezone"],"additionalProperties":false},"asOf":{"type":"string"},"open":{"type":"boolean"},"totals":{"type":"object","properties":{"here":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expected":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"taken":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["here","expected","taken","capacity"],"additionalProperties":false},"onNow":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["class","appointment","rental","open_room"]},"occurrenceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"room":{"anyOf":[{"type":"string"},{"type":"null"}]},"roomId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"taken":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"here":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expected":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"walkIns":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["kind","occurrenceId","offeringId","name","room","roomId","startsAt","endsAt","capacity","taken","here","expected","walkIns"],"additionalProperties":false}},"rooms":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"taken":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"here":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"open":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"walkIn":{"type":"boolean"}},"required":["id","name","capacity","taken","here","open","walkIn"],"additionalProperties":false}},"walkIn":{"type":"object","properties":{"configured":{"type":"boolean"},"available":{"type":"boolean"},"spotsOpen":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"level":{"anyOf":[{"type":"string","enum":["plenty","filling_up","nearly_full","full"]},{"type":"null"}]},"nextSpotsAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["configured","available","spotsOpen","capacity","level","nextSpotsAt"],"additionalProperties":false},"changesAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["location","asOf","open","totals","onNow","rooms","walkIn","changesAt"],"additionalProperties":false},"ChatStreamNote":{"type":"object","properties":{"note":{"type":"string"}},"required":["note"],"additionalProperties":false,"description":"Placeholder. This endpoint responds with `text/event-stream`, not JSON. Events: `message_start`, `text_delta`, `tool_start`, `tool_end`, `proposal`, `error`, `done`. A comment heartbeat is sent every 15 seconds so intermediaries do not close the stream."},"SetupChatResume":{"type":"object","properties":{"session":{"anyOf":[{},{"type":"null"}]},"messages":{"type":"array","items":{}},"draft":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"hasBusiness":{"type":"boolean"}},"required":["session","messages","draft","hasBusiness"],"additionalProperties":false},"SetupDraftPatchResult":{"type":"object","properties":{"session":{},"draft":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"hasBusiness":{"type":"boolean"}},"required":["session","draft","hasBusiness"],"additionalProperties":false},"SetupPreviewHtml":{"type":"string"},"SetupDraftView":{"type":"object","properties":{"draft":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"hasBusiness":{"type":"boolean"}},"required":["draft","hasBusiness"],"additionalProperties":false},"SetupCommitResult":{"type":"object","properties":{"businessId":{"type":"string"},"locationId":{"type":"string"},"name":{"type":"string"},"storefrontUrl":{"type":"string"},"catalog":{"type":"string"},"rows":{"type":"string"},"hidden":{"type":"array","items":{"type":"string"}},"draft":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["businessId","locationId","name","storefrontUrl","catalog","rows","hidden","draft"],"additionalProperties":false},"SetupApplySiteResult":{"type":"object","properties":{"draft":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"applied":{"type":"boolean"}},"required":["draft","applied"],"additionalProperties":false},"ChatSession":{"type":"object","properties":{"id":{"type":"string"},"businessId":{"type":"string"},"locationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"tokenBudgetUsed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"archivedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","businessId","locationId","title","tokenBudgetUsed","createdAt","updatedAt","archivedAt"],"additionalProperties":false},"ChatMessage":{"type":"object","properties":{"id":{"type":"string"},"sessionId":{"type":"string"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"role":{"type":"string","enum":["user","assistant","tool"]},"content":{},"toolName":{"anyOf":[{"type":"string"},{"type":"null"}]},"toolCallId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","sessionId","seq","role","content","toolName","toolCallId","createdAt"],"additionalProperties":false},"InlineListingProposal":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"summary":{"type":"string"},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"schedules":{"type":"array","items":{"$ref":"#/components/schemas/InlineScheduleDraftOutput"}},"instructorIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"instructorsToCreate":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"},"bio":{"type":"string"},"specialties":{"type":"array","items":{"type":"string"}}},"required":["name"],"additionalProperties":false}},"expiresAt":{"type":"string"},"signature":{"type":"string"}},"required":["proposalId","summary","fields","schedules","instructorIds","instructorsToCreate","expiresAt","signature"],"additionalProperties":false},"InlinePlanProposal":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"summary":{"type":"string"},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"expiresAt":{"type":"string"},"signature":{"type":"string"}},"required":["proposalId","summary","fields","expiresAt","signature"],"additionalProperties":false},"InlineEmbedCssProposal":{"type":"object","properties":{"css":{"anyOf":[{"type":"string"},{"type":"null"}]},"reply":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"line":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"level":{"type":"string","enum":["refuse","warn"]},"code":{"type":"string","enum":["size","braces","import","font-face","at-rule","legacy","url","unscoped","important"]},"message":{"type":"string"}},"required":["line","level","code","message"],"additionalProperties":false}}},"required":["css","reply","issues"],"additionalProperties":false},"FormattedMarkdown":{"type":"object","properties":{"markdown":{"type":"string"}},"required":["markdown"],"additionalProperties":false},"ListingMarkPick":{"type":"object","properties":{"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A picker icon key, or null for the kind’s own glyph."},"color":{"type":"string","description":"The swatch’s hex."},"source":{"type":"string","enum":["model","rule"]}},"required":["icon","color","source"],"additionalProperties":false},"RewrittenMarkdown":{"type":"object","properties":{"markdown":{"type":"string"}},"required":["markdown"],"additionalProperties":false},"HealthReport":{"type":"object","properties":{"status":{"type":"string","const":"ok"},"db":{"type":"string","const":"up"},"uptimeSeconds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"timestamp":{"$ref":"#/components/schemas/Timestamp"}},"required":["status","db","uptimeSeconds","timestamp"],"additionalProperties":false,"example":{"status":"ok","db":"up","uptimeSeconds":3600,"timestamp":"2026-07-24T12:00:00.000Z"}},"WorkerHealthReport":{"type":"object","properties":{"status":{"type":"string","const":"ok"},"worker":{"type":"string","const":"up"},"overdueTasks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"oldestOverdueSeconds":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"timestamp":{"$ref":"#/components/schemas/Timestamp"}},"required":["status","worker","overdueTasks","oldestOverdueSeconds","timestamp"],"additionalProperties":false,"example":{"status":"ok","worker":"up","overdueTasks":0,"oldestOverdueSeconds":null,"timestamp":"2026-07-24T12:00:00.000Z"}},"RequestChallengeResult":{"type":"object","properties":{"challengeId":{"$ref":"#/components/schemas/Uuid"},"channel":{"$ref":"#/components/schemas/VerificationChannel"},"expiresAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["challengeId","channel","expiresAt"],"additionalProperties":false,"example":{"challengeId":"550e8400-e29b-41d4-a716-446655440017","channel":"email_code","expiresAt":"2026-08-01T18:00:00.000Z"}},"VerifyChallengeResult":{"type":"object","properties":{"sessionToken":{"type":"string","description":"Bearer token for subsequent authenticated requests","example":"sess_example_token_not_a_real_secret"},"sessionExpiresAt":{"$ref":"#/components/schemas/Timestamp"},"person":{"$ref":"#/components/schemas/Person"},"claimed":{"type":"array","items":{"type":"object","properties":{"businessName":{"type":"string"}},"required":["businessName"],"additionalProperties":false}}},"required":["sessionToken","sessionExpiresAt","person","claimed"],"additionalProperties":false,"example":{"sessionToken":"sess_example_token_not_a_real_secret","sessionExpiresAt":"2026-08-01T18:00:00.000Z","person":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"claimed":[{"businessName":"River Studio"}]}},"Person":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalGivenName":{"anyOf":[{"type":"string"},{"type":"null"}]},"legalFamilyName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"$ref":"#/components/schemas/Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","displayName","legalGivenName","legalFamilyName","email","phone","createdAt","updatedAt"],"additionalProperties":false,"description":"A person identity in Bookable","example":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"SignOutResult":{"type":"object","properties":{"signedOut":{"type":"boolean"}},"required":["signedOut"],"additionalProperties":false,"example":{"signedOut":true}},"Closure":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"resourceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"instructorId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"reason":{"type":"string"},"allDay":{"type":"boolean"},"seriesId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"affectedBookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","businessId","locationId","resourceId","instructorId","startsAt","endsAt","reason","allDay","seriesId","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440014","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","resourceId":null,"instructorId":null,"startsAt":"2026-12-25T05:00:00.000Z","endsAt":"2026-12-26T05:00:00.000Z","reason":"Christmas Day","allDay":true,"seriesId":"550e8400-e29b-41d4-a716-446655440014","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","affectedBookings":0}},"HolidaySuggestion":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"date":{"type":"string"}},"required":["key","name","date"],"additionalProperties":false,"example":{"key":"thanksgiving","name":"Thanksgiving","date":"2026-11-26"}},"CalendarFeedsPayload":{"type":"object","properties":{"locationName":{"type":"string"},"hasClasses":{"type":"boolean"},"hasReservationListings":{"type":"boolean"},"teachesHere":{"type":"boolean"},"soloTeam":{"type":"boolean"},"canManage":{"type":"boolean"},"spaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"hasFeed":{"type":"boolean"}},"required":["id","name","hasFeed"],"additionalProperties":false}},"feeds":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["studio","space","teaching"]},"resourceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"resourceName":{"anyOf":[{"type":"string"},{"type":"null"}]},"personId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"name":{"type":"string"},"token":{"type":"string"},"subscribeUrl":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","kind","resourceId","resourceName","personId","name","token","subscribeUrl","createdAt"],"additionalProperties":false}}},"required":["locationName","hasClasses","hasReservationListings","teachesHere","soloTeam","canManage","spaces","feeds"],"additionalProperties":false},"CalendarFeed":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["studio","space","teaching"]},"resourceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"resourceName":{"anyOf":[{"type":"string"},{"type":"null"}]},"personId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"name":{"type":"string"},"token":{"type":"string"},"subscribeUrl":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","kind","resourceId","resourceName","personId","name","token","subscribeUrl","createdAt"],"additionalProperties":false},"CalendarFeedRotated":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["studio","space","teaching"]},"resourceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"resourceName":{"anyOf":[{"type":"string"},{"type":"null"}]},"personId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"name":{"type":"string"},"token":{"type":"string"},"subscribeUrl":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","kind","resourceId","resourceName","personId","name","token","subscribeUrl","createdAt"],"additionalProperties":false},"Resource":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"kind":{"type":"string","enum":["room","equipment"]},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"positionLayout":{"type":"string","enum":["list","grid"]},"hoursByDay":{"anyOf":[{"type":"object","properties":{"mon":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"],"additionalProperties":false},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"],"additionalProperties":false}]},"tue":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"],"additionalProperties":false},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"],"additionalProperties":false}]},"wed":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"],"additionalProperties":false},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"],"additionalProperties":false}]},"thu":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"],"additionalProperties":false},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"],"additionalProperties":false}]},"fri":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"],"additionalProperties":false},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"],"additionalProperties":false}]},"sat":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"],"additionalProperties":false},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"],"additionalProperties":false}]},"sun":{"anyOf":[{"type":"object","properties":{"closed":{"type":"boolean","const":true}},"required":["closed"],"additionalProperties":false},{"type":"object","properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = opens with the location."},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`HH:MM`; null = closes with the location."}},"required":["start","end"],"additionalProperties":false}]}},"additionalProperties":false},{"type":"null"}],"description":"The days whose hours differ from the location's (build-plan/196): each opens later, closes earlier, or is closed. A day not listed, or null, follows the location."},"seating":{"type":"string","enum":["booked","door"],"description":"How a room with tables seats its parties (build-plan/247). `booked`: each booking takes a table as it is made, and a party no table fits cannot book. `door`: times sell by the tables' seats, and the host seats parties as they arrive. Means nothing without tables. A new room starts at the door."},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"positions":{"type":"array","items":{"$ref":"#/components/schemas/ResourcePosition"}},"tables":{"type":"array","items":{"$ref":"#/components/schemas/ResourceTable"},"description":"Empty in spots mode. When present, capacity is the sum of these tables."},"imageUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The room's first photo (small cut), or null — what the console's Spaces list shows beside the name."}},"required":["id","businessId","locationId","kind","name","description","capacity","positionLayout","hoursByDay","seating","createdAt","updatedAt","archivedAt","positions","tables","imageUrl"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440007","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","kind":"room","name":"Studio A","description":"Heated room with mirrors","capacity":20,"positionLayout":"list","hoursByDay":{"sat":{"start":"11:00","end":null},"sun":{"closed":true}},"seating":"door","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null,"imageUrl":null,"positions":[{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":0,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":1,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":2,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":3,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":4,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":5,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":6,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":7,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":8,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":9,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":10,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":11,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":12,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":13,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":14,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":15,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":16,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":17,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":18,"name":null,"tableId":null},{"id":"550e8400-e29b-41d4-a716-446655440007","sortIndex":19,"name":null,"tableId":null}],"tables":[]}},"ResourcePosition":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"sortIndex":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"tableId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}},"required":["id","sortIndex","name"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440030","sortIndex":0,"name":"Window","tableId":null}},"ResourceTable":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"shape":{"type":"string","enum":["round","square","rect","booth"]},"share":{"type":"boolean"},"x":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Left edge on the 1000 × 600 room map."},"y":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Top edge on the 1000 × 600 room map."},"width":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rotation":{"anyOf":[{"type":"number","const":0},{"type":"number","const":90},{"type":"number","const":180},{"type":"number","const":270}],"description":"Clockwise quarter turn: which edge a booth's back and a long table's chairs sit on. The box is already the turned footprint."},"sortIndex":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","name","spots","shape","share","x","y","width","height","rotation","sortIndex"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440031","name":"Window","spots":2,"shape":"round","share":false,"x":20,"y":20,"width":70,"height":70,"rotation":0,"sortIndex":0}},"InstructorProfile":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"personId":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"bio":{"type":"string"},"headshotUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"specialties":{"type":"array","items":{"type":"string"}},"public":{"type":"boolean"},"instagram":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Instagram handle, without @. Used as a post collaborator and a Story @mention."},"notifyBookings":{"type":"boolean","description":"Email or text when someone books, cancels, or moves a time they teach. On unless turned off."},"locationIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"hours":{"type":"array","items":{"$ref":"#/components/schemas/InstructorHours"},"description":"Own bookable windows per site, one entry per assigned location. Empty scheduleIds = follows that location's open hours (build-plan/162)."},"reservationIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"Reservations (offerings of type session) this person delivers (live rows)."},"person":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"email":{"$ref":"#/components/schemas/Email"},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","email","displayName"],"additionalProperties":false},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","personId","businessId","bio","headshotUrl","specialties","public","instagram","notifyBookings","locationIds","hours","reservationIds","person","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440008","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","bio":"RYT-200 yoga instructor","headshotUrl":"https://cdn.example.com/alex.jpg","specialties":["vinyasa","restorative"],"public":true,"instagram":"alexrivera","notifyBookings":true,"locationIds":["550e8400-e29b-41d4-a716-446655440003"],"hours":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","scheduleIds":[]}],"reservationIds":[],"person":{"id":"550e8400-e29b-41d4-a716-446655440001","email":"alex@example.com","displayName":"Alex Rivera"},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"InstructorHours":{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"},"scheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}},"required":["locationId","scheduleIds"],"additionalProperties":false,"example":{"locationId":"550e8400-e29b-41d4-a716-446655440003","scheduleIds":[]}},"Offering":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"type":{"type":"string","enum":["class","session","space"]},"exclusive":{"type":"boolean"},"customerWord":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The group this listing sits in — a preset or a name this studio typed. Null follows the business word for its kind (build-plan/190)."},"name":{"type":"string"},"slug":{"type":"string"},"slugIsCustom":{"type":"boolean"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"level":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Short level label — e.g. Beginner, All levels (build-plan/72)."},"whatToBring":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What to bring — plain text or short markdown (build-plan/72)."},"color":{"type":"string","description":"The color this listing wears in the console — calendar, bookings, and today. A #rrggbb, a swatch name (red, clay, blue, …), or a category name. Auto-assigned hash(id) % 8 on create when none is picked."},"icon":{"anyOf":[{"type":"string","enum":["artboard","glass-full","wheel","hands","mug","brush","glass","flame","pencil","cookie","palette","door","moon","heart","users","kid","senior","tent","series","tools","cake","lock","team","school","fundraiser","tree","pumpkin","leaf","hearts","egg","flower","tie","star","confetti","skull","sun","ticket","gift-card","building","cash","beach","graduation-cap","dumbbell","kettlebell","biceps","person-standing","heart-pulse","timer","zap","bike","footprints","waves","user","baby","paintbrush","amphora","hand","scissors","sparkles","music","mic","camera","utensils","coffee","book"]},{"type":"null"}],"description":"The icon this listing wears in the console, in `color`. A picker key, or its label. Null wears the kind's own glyph (a cap for a class, a workout for a reservation)."},"status":{"type":"string","enum":["draft","published","hidden","archived"]},"lifecycle":{"type":"string","enum":["live","upcoming","ended","unscheduled"]},"nextOccurrenceAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"lastOccurrenceAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"$ref":"#/components/schemas/Currency"},"taxable":{"type":"boolean","description":"Sales tax applies at the rates in Settings (architecture/05 § Tax). Default true; inert until the business holds rates."},"revenueCategoryId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"What this is in the studio's books and which taxes it carries (architecture/31). With one, `taxable` is inert. Null = none."},"priceParts":{"type":"array","items":{"type":"object","properties":{"amount":{"description":"Per unit — per spot, or per booking on a buyout.","$ref":"#/components/schemas/MoneyAmount"},"revenueCategoryId":{"$ref":"#/components/schemas/Uuid"},"revenueCategoryName":{"type":"string"}},"required":["amount","revenueCategoryId","revenueCategoryName"],"additionalProperties":false},"description":"The price split across revenue categories — \"$10 is Materials\" — in the order a receipt itemizes them. Never summing above priceAmount; the rest follows revenueCategoryId (architecture/31)."},"priceTiers":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"label":{"type":"string"},"priceAmount":{"description":"Per booking for a package, per spot for a seat price.","$ref":"#/components/schemas/MoneyAmount"},"unit":{"type":"string","enum":["booking","spot"]},"minQty":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxQty":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"extraAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}],"description":"A package's amount per spot past maxQty; it then sells to the spots left. Null: it stops at maxQty (build-plan/290)."}},"required":["id","label","priceAmount","unit","minQty","maxQty","extraAmount"],"additionalProperties":false},"description":"Named prices beside the base, in the order they sell (architecture/03 § Price tiers). A `booking` tier is a package — \"4 people $110\": a headcount from minQty to maxQty, priced once, taking that many spots. A `spot` tier is a named seat price — \"Child $15\" — picked minQty to maxQty at a time and mixed with the others and the base. The base price always sells."},"depositType":{"type":"string","enum":["none","fixed","percent"]},"depositAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"minPartySize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Spots per booking: the fewest one online booking takes. Null = no limit."},"maxPartySize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Spots per booking: the most one online booking takes. Null = no limit."},"largerPartyOfferingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"The listing a group above `maxPartySize` is pointed to on the public page."},"creditCost":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Credits required to cover one spot (architecture/05). Default 1; 0 is free without consuming credits."},"durationMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"slotGranularityMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bookingHorizonDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Effective — this listing's own rule, else the business default (Settings → Booking)."},"bookingCutoffMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Effective; 0 = booking stays open until start."},"cancellationCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Effective; null = any time before start; -1 = no cancellation."},"rescheduleCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Effective change-time window; null = until the start; -1 = no changes."},"spotsLeft":{"type":"string","enum":["few","always"],"description":"Effective Spots left — this listing's own, else the business setting (build-plan/238)."},"bookingRuleOverrides":{"type":"object","properties":{"horizonDays":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"cutoffMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"cancellationCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"rescheduleCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"spotsLeft":{"anyOf":[{"type":"string","enum":["few","always"]},{"type":"null"}]}},"required":["horizonDays","cutoffMinutes","cancellationCutoffHours","rescheduleCutoffHours","spotsLeft"],"additionalProperties":false,"description":"What this listing set itself; null follows the business default. cancellationCutoffHours 0 is an explicit \"any time\"."},"priceName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The first price's name; null reads \"Spot\" (build-plan/215)."},"priceUnit":{"type":"string","enum":["spot","booking"],"description":"The first price is per person (spot) or for the group (booking)."},"priceExtraAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}],"description":"A group first price's amount per spot past maxPartySize; null: the group stops there (build-plan/290)."},"pricing":{"type":"string","enum":["standard","subscription"],"description":"How it is priced (build-plan/280): standard pays when they book; subscription holds spots in every session it covers and bills per spot every term."},"billingTerm":{"anyOf":[{"type":"string","enum":["weekly","monthly"]},{"type":"null"}],"description":"A subscription's term; null on a standard listing."},"subscribeTo":{"anyOf":[{"type":"string","enum":["every_session","one_time_a_week"]},{"type":"null"}],"description":"Which sessions a subscription covers: every session on the timetable, or one weekly time the customer picks. An appointment is always one time a week. Null on a standard listing."},"resourceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"tableIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"The tables it seats at in its room, in the room's order; empty is every table (build-plan/214)."},"instructorIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"requiredAccessKeys":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Customers enter it to see and book this listing; null = none. A convenience, kept as written."},"showOnPage":{"type":"boolean","description":"On the studio's pages, or (false, with a password) only by its link."},"confirmationMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"meetingUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"https link included on the confirmation and the day-of reminder. Null sends nothing."},"meetingInstructions":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Short note sent with the meeting link. Null sends nothing."},"place":{"type":"string","enum":["on_site","off_site","online"],"description":"Where it is held. on_site: at its location, in its space (resourceId) if any. off_site: placeName and placeAddress, no room. online: meetingUrl joins it, no room."},"placeName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Off site: the place's name. Null elsewhere."},"placeAddress":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Off site: the place's address. Null elsewhere."},"placeLat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Off site: the address's pin, when known."},"placeLng":{"anyOf":[{"type":"number"},{"type":"null"}]},"placeNote":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Off site: where in the place to go — shown under the address on the listing and in the confirmation and reminder. Null elsewhere."},"scheduleIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"windows":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"timezone":{"type":"string"},"rrule":{"type":"string"},"startDate":{"type":"string"},"until":{"anyOf":[{"type":"string"},{"type":"null"}]},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","name","timezone","rrule","startDate","until","durationMinutes"],"additionalProperties":false},"description":"The listing's own hours (build-plan/282 T6): on a session or space listing, the weekly windows its scheduleIds bind — inside the room's or the people's hours, from startDate until until. Empty follows the host's hours; always empty on a class."},"questionIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"Ordered checkout questions (architecture/16 § Questions at checkout)"},"questionPrices":{"type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"prices":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]}}},"required":["questionId","prices"],"additionalProperties":false},"description":"The questions asked for some of the listing's prices only (build-plan/239 § 7), each with the prices that ask it — a tier's id, null for the first price. A question not named asks every price. A booking asks one once when what it bought includes one of them."},"agreementDocumentIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"Waivers & terms (architecture/33): the documents customers agree to when they book this, in order."},"productIds":{"type":"array","items":{"type":"object","properties":{"productId":{"$ref":"#/components/schemas/Uuid"},"required":{"type":"boolean"},"maxPerSpot":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["productId","required","maxPerSpot"],"additionalProperties":false},"description":"Ordered add-ons (`offering_product`). Replace-all on write, like questionIds (architecture/26)."},"missingRequiredAddons":{"type":"array","items":{"type":"string"},"description":"Required add-on names detached when their product was archived. Publish refuses until a replacement is attached."},"images":{"type":"array","items":{"$ref":"#/components/schemas/OfferingImage"}},"displayOrder":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Operator-controlled catalog order within (location, type) — build-plan/93."},"dropInEnabled":{"type":"boolean","description":"When false, the class sells series runs only — no single-night drop-in (build-plan/154)."},"personChoice":{"type":"string","enum":["customer","any"],"description":"Reservations: `customer` — the storefront offers Anyone plus each public person in the pool; `any` — no person step, the studio assigns in instructorIds order. Read as `any` with one person (build-plan/162)."},"subscriberCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"A subscription listing's live subscribers, on the single read (build-plan/280); null elsewhere."},"nextSeriesStartsAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"Start of the next published series date on this offering, if any."},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","locationId","type","exclusive","customerWord","name","slug","slugIsCustom","description","level","whatToBring","color","icon","status","lifecycle","nextOccurrenceAt","lastOccurrenceAt","priceAmount","priceCurrency","taxable","revenueCategoryId","priceParts","priceTiers","depositType","depositAmount","capacity","minPartySize","maxPartySize","largerPartyOfferingId","creditCost","durationMinutes","slotGranularityMinutes","bookingHorizonDays","bookingCutoffMinutes","cancellationCutoffHours","rescheduleCutoffHours","spotsLeft","bookingRuleOverrides","priceName","priceUnit","priceExtraAmount","pricing","billingTerm","subscribeTo","resourceId","tableIds","instructorIds","requiredAccessKeys","password","showOnPage","confirmationMessage","meetingUrl","meetingInstructions","place","placeName","placeAddress","placeLat","placeLng","placeNote","scheduleIds","windows","questionIds","questionPrices","agreementDocumentIds","productIds","missingRequiredAddons","images","displayOrder","dropInEnabled","personChoice","subscriberCount","nextSeriesStartsAt","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440004","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","exclusive":false,"name":"Morning Flow","slug":"morning-flow","slugIsCustom":false,"description":"All-levels vinyasa","level":"All levels","whatToBring":"A mat and water.","color":"clay","icon":null,"status":"published","lifecycle":"live","nextOccurrenceAt":"2026-07-24T12:00:00.000Z","lastOccurrenceAt":"2026-07-24T12:00:00.000Z","priceAmount":3000,"priceCurrency":"USD","taxable":true,"revenueCategoryId":null,"priceParts":[],"priceTiers":[],"depositType":"percent","depositAmount":50,"capacity":20,"minPartySize":null,"maxPartySize":null,"largerPartyOfferingId":null,"creditCost":1,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always","bookingRuleOverrides":{"horizonDays":30,"cutoffMinutes":60,"cancellationCutoffHours":24,"rescheduleCutoffHours":24,"spotsLeft":"always"},"resourceId":"550e8400-e29b-41d4-a716-446655440007","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"requiredAccessKeys":null,"password":null,"showOnPage":true,"confirmationMessage":null,"meetingUrl":null,"meetingInstructions":null,"place":"on_site","placeName":null,"placeAddress":null,"placeLat":null,"placeLng":null,"placeNote":null,"scheduleIds":["550e8400-e29b-41d4-a716-446655440014"],"questionIds":[],"questionPrices":[],"agreementDocumentIds":[],"productIds":[],"missingRequiredAddons":[],"images":[{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}],"displayOrder":0,"dropInEnabled":true,"personChoice":"customer","nextSeriesStartsAt":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"OfferingImage":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"url":{"type":"string"},"sortOrder":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","offeringId","url","sortOrder","createdAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440019","offeringId":"550e8400-e29b-41d4-a716-446655440004","url":"https://cdn.example.com/class.jpg","sortOrder":0,"createdAt":"2026-07-24T12:00:00.000Z"}},"AvailabilityExplanation":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"offeringName":{"type":"string"},"day":{"type":"string","description":"YYYY-MM-DD in the location's zone."},"timezone":{"type":"string"},"subject":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["space","person"]},"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["kind","id","name"],"additionalProperties":false},{"type":"null"}],"description":"The room, or the one person of the pool explained; null when the listing has neither yet."},"subjects":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"description":"The pool a reservation may be explained for, one at a time (`subjectId`); one entry for a rental."},"dayReasons":{"type":"array","items":{"$ref":"#/components/schemas/ExplainReason"},"description":"What holds for every start of the day, said once."},"starts":{"type":"array","items":{"$ref":"#/components/schemas/ExplainStart"},"description":"Every start the hours allow that day, in order, before anything is taken away."}},"required":["offeringId","offeringName","day","timezone","subject","subjects","dayReasons","starts"],"additionalProperties":false,"example":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Table Reservation","day":"2026-10-07","timezone":"America/New_York","subject":{"kind":"space","id":"550e8400-e29b-41d4-a716-446655440007","name":"Studio"},"subjects":[{"id":"550e8400-e29b-41d4-a716-446655440007","name":"Studio"}],"dayReasons":[],"starts":[{"occurrenceId":"550e8400-e29b-41d4-a716-446655440004:550e8400-e29b-41d4-a716-446655440007:2026-10-07T20:00:00.000Z","startsAt":"2026-10-07T20:00:00.000Z","endsAt":"2026-10-07T22:00:00.000Z","label":"4:00 PM","state":"reduced","left":6,"total":18,"maxPartySize":null,"reasons":[{"kind":"class","text":"Story Time Art · 4:30 – 5:00 PM · 12 spots · holds Six-Top, Four-Top 1","href":"/listings?id=550e8400-e29b-41d4-a716-446655440004&occurrence=550e8400-e29b-41d4-a716-446655440014%3A2026-10-07T20%3A30%3A00.000Z","seats":12}]}]}},"ExplainReason":{"type":"object","properties":{"kind":{"type":"string","enum":["closed","time_off","hours","offered","cutoff","horizon","google","busy","class","booking","claim","own","tables"],"description":"What it is: a closure, a person's time off, no hours, not offered then, before the cutoff, past the horizon, Google busy time, something that takes the whole time (a class a person teaches, a buyout, an appointment), a class date in the room, another party, seats sold elsewhere, this listing's own booking, or the tables' cap."},"text":{"type":"string","description":"Plain words: `Story Time Art · 4:30 – 5:00 PM · 12 spots`."},"href":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A console path to the thing (`/bookings?id=…`, `/listings?id=…&occurrence=…`), or null."},"seats":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The seats it takes from this listing then, when it is load."}},"required":["kind","text","href","seats"],"additionalProperties":false},"ExplainStart":{"type":"object","properties":{"occurrenceId":{"type":"string"},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"label":{"type":"string","description":"`4:00 PM`, in the location's zone."},"state":{"type":"string","enum":["open","reduced","full","gone"],"description":"open: every seat; reduced: fewer, and the reasons say who has the rest; full; gone: not for sale, and the reasons say what took it."},"left":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"total":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"maxPartySize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"reasons":{"type":"array","items":{"$ref":"#/components/schemas/ExplainReason"}}},"required":["occurrenceId","startsAt","endsAt","label","state","left","total","maxPartySize","reasons"],"additionalProperties":false},"ListingOverview":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"timezone":{"type":"string"},"upcoming":{"type":"array","items":{"$ref":"#/components/schemas/ListingOverviewScheduleClassRow"}}},"required":["offeringId","timezone","upcoming"],"additionalProperties":false},"ListingOverviewScheduleClassRow":{"type":"object","properties":{"kind":{"type":"string","enum":["class","rental"]},"occurrenceId":{"type":"string"},"offeringId":{"type":"string"},"offeringName":{"type":"string"},"offeringStatus":{"type":"string","enum":["draft","published","hidden","archived"]},"localStart":{"type":"string"},"localEnd":{"type":"string"},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"capacityTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacityBooked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacityRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacityByStatus":{"$ref":"#/components/schemas/ScheduleCapacityByStatus"},"instructorIds":{"type":"array","items":{"type":"string"}},"instructors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"headshotUrl":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","headshotUrl"],"additionalProperties":false}},"instructorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"instructorHeadshotUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"spaceName":{"anyOf":[{"type":"string"},{"type":"null"}]},"listingImageUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"stranded":{"$ref":"#/components/schemas/StrandedReason"}},"required":["kind","occurrenceId","offeringId","offeringName","offeringStatus","localStart","localEnd","startsAt","endsAt","capacityTotal","capacityBooked","capacityRemaining","capacityByStatus","instructorIds","instructors","instructorName","instructorHeadshotUrl","spaceName","listingImageUrl","stranded"],"additionalProperties":false},"ListingShare":{"type":"object","properties":{"url":{"type":"string"},"name":{"type":"string"},"details":{"type":"string"},"priceAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"priceCurrency":{"type":"string"},"imageUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"blocked":{"anyOf":[{"type":"string","enum":["draft","hidden","archived","password"]},{"type":"null"}]}},"required":["url","name","details","priceAmount","priceCurrency","imageUrl","blocked"],"additionalProperties":false},"Series":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"type":"string"},"status":{"type":"string","enum":["draft","published","hidden","archived"]},"startsOn":{"type":"string","description":"First candidate day (YYYY-MM-DD) in the schedule timezone."},"sessionCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"activeSessionCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"endsOn":{"anyOf":[{"type":"string"},{"type":"null"}]},"startsAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"endsAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"$ref":"#/components/schemas/Currency"},"creditCost":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"enrollmentClosesAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"enrollmentOpen":{"type":"boolean"},"spotsRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"enrolledCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"occurrences":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"scheduleId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"timezone":{"type":"string"},"capacityOverride":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"resourceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"seriesId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"instructorIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"status":{"type":"string","enum":["scheduled","canceled","completed"]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","scheduleId","offeringId","startsAt","endsAt","timezone","capacityOverride","resourceId","seriesId","instructorIds","status","createdAt","updatedAt","archivedAt"],"additionalProperties":false}},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","locationId","offeringId","name","displayName","status","startsOn","sessionCount","activeSessionCount","endsOn","startsAt","endsAt","priceAmount","priceCurrency","creditCost","enrollmentClosesAt","enrollmentOpen","spotsRemaining","enrolledCount","occurrences","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440024","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","name":"Intro to Pottery, Sep 15 – Oct 20","displayName":"Intro to Pottery, Sep 15 – Oct 20","status":"published","startsOn":"2026-09-15","sessionCount":6,"activeSessionCount":6,"endsOn":"2026-10-20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","priceAmount":24000,"priceCurrency":"USD","creditCost":null,"enrollmentClosesAt":null,"enrollmentOpen":true,"spotsRemaining":8,"enrolledCount":0,"occurrences":[{"id":"550e8400-e29b-41d4-a716-446655440014:2026-09-15T23:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-09-16T01:00:00.000Z","timezone":"America/Denver","capacityOverride":null,"resourceId":"550e8400-e29b-41d4-a716-446655440007","seriesId":"550e8400-e29b-41d4-a716-446655440024","instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"SeriesOverview":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"displayName":{"type":"string"},"startsAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"endsAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"status":{"type":"string","enum":["draft","published","hidden","archived"]},"sessionCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"activeSessionCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"enrolledCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"spotsRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"moneyCollected":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"sessions":{"type":"array","items":{"type":"object","properties":{"occurrenceId":{"type":"string"},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"timezone":{"type":"string"},"status":{"type":"string"},"bookedCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"checkedInCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["occurrenceId","startsAt","endsAt","timezone","status","bookedCount","checkedInCount"],"additionalProperties":false}},"enrollments":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"reference":{"type":"string"},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"customerName":{"type":"string"},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["held","confirmed","canceled"]},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"amountPaid":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"moneyEffects":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"currency":{"type":"string"},"movements":{"type":"array","items":{"type":"object","properties":{"direction":{"type":"string","enum":["charge","refund","forfeit"]},"instrument":{"type":"string","enum":["card","cash","credits"]},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"label":{"type":"string"}},"required":["direction","instrument","amount","label"],"additionalProperties":false}},"requiresApproval":{"type":"boolean"},"summary":{"type":"string"}},"required":["action","currency","movements","requiresApproval","summary"],"additionalProperties":false}}},"required":["id","reference","customerId","customerName","partySize","status","amountTotal","amountPaid","currency","moneyEffects"],"additionalProperties":false}}},"required":["id","offeringId","displayName","startsAt","endsAt","status","sessionCount","activeSessionCount","capacity","enrolledCount","spotsRemaining","moneyCollected","currency","sessions","enrollments"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440024","offeringId":"550e8400-e29b-41d4-a716-446655440004","displayName":"Intro to Pottery, Sep 15 – Oct 20","startsAt":"2026-09-15T23:00:00.000Z","endsAt":"2026-10-20T01:00:00.000Z","status":"published","sessionCount":6,"activeSessionCount":6,"capacity":8,"enrolledCount":1,"spotsRemaining":7,"moneyCollected":24000,"currency":"USD","sessions":[],"enrollments":[]}},"Occurrence":{"type":"object","properties":{"id":{"type":"string"},"scheduleId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"timezone":{"type":"string"},"capacityOverride":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"resourceId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"seriesId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"instructorIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}},"status":{"type":"string","enum":["scheduled","canceled","completed"]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","scheduleId","offeringId","startsAt","endsAt","timezone","capacityOverride","resourceId","seriesId","instructorIds","status","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","offeringId":"550e8400-e29b-41d4-a716-446655440004","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","timezone":"America/Los_Angeles","capacityOverride":null,"resourceId":null,"seriesId":null,"instructorIds":["550e8400-e29b-41d4-a716-446655440008"],"status":"scheduled","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"RemovedOccurrence":{"type":"object","properties":{"occurrenceId":{"type":"string"},"offeringId":{"type":"string"},"scheduleId":{"type":"string"},"scheduleDeleted":{"type":"boolean","description":"The rule went with its only date. False when another class still runs on it, or history still points at it (then it is archived)."}},"required":["occurrenceId","offeringId","scheduleId","scheduleDeleted"],"additionalProperties":false,"example":{"occurrenceId":"0192b4d1-2f2a-7a5e-9d3c-0d7a1c2b3e4f:2026-09-16T18:00:00.000Z","offeringId":"0192b4d1-2f2a-7a5e-9d3c-0d7a1c2b3e50","scheduleId":"0192b4d1-2f2a-7a5e-9d3c-0d7a1c2b3e4f","scheduleDeleted":true}},"OccurrenceSlot":{"type":"object","properties":{"occurrenceId":{"type":"string","description":"Stable moment key. Classes: `scheduleId:startUtc`. Reservations and rentals: `offeringId:subjectId:startUtc`, where the subject is the team member (reservation) or space (rental); `any` in place of the subject is a customer's open pick that the hold resolves in pool order."},"scheduleId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"The class schedule projected; null for reservation and rental grids."},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"localStart":{"type":"string"},"localEnd":{"type":"string"},"timezone":{"type":"string"},"capacityTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"capacityRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxPartySize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Largest party a table can still take, capped by the seats left. 0 reads full. Null when the room has no tables, or the listing sells the whole space."},"capacityByStatus":{"$ref":"#/components/schemas/ScheduleCapacityByStatus"},"status":{"type":"string","enum":["open","full","blacked_out","closed"]},"materialized":{"type":"boolean"},"instructorIds":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"},"description":"Reservations only: team members who can take this start. The occurrenceId names one of them when exactly one is free, else `any`. Empty for classes and rentals."},"stranded":{"$ref":"#/components/schemas/StrandedReason"}},"required":["occurrenceId","scheduleId","startsAt","endsAt","localStart","localEnd","timezone","capacityTotal","capacityRemaining","maxPartySize","capacityByStatus","status","materialized","instructorIds","stranded"],"additionalProperties":false,"example":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","localStart":"2026-08-01T12:00:00","localEnd":"2026-08-01T13:00:00","timezone":"America/Denver","capacityTotal":20,"capacityRemaining":5,"maxPartySize":null,"capacityByStatus":{"held":0,"confirmed":5,"completed":0,"noShow":0,"elsewhere":0},"status":"open","materialized":false,"instructorIds":[]}},"IsLocationOpenResult":{"type":"object","properties":{"open":{"type":"boolean"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["open","reason"],"additionalProperties":false,"example":{"open":true,"reason":null}},"TimelineItem":{"type":"object","properties":{"kind":{"type":"string","enum":["event","task"]},"id":{"$ref":"#/components/schemas/Uuid"},"type":{"type":"string"},"at":{"$ref":"#/components/schemas/Timestamp"},"status":{"type":"string"},"event":{"$ref":"#/components/schemas/EventEnvelope"},"task":{"$ref":"#/components/schemas/ScheduledTask"}},"required":["kind","id","type","at"],"additionalProperties":false,"example":{"kind":"event","id":"550e8400-e29b-41d4-a716-446655440020","type":"booking.created","at":"2026-07-24T12:00:00.000Z","event":{"id":"550e8400-e29b-41d4-a716-446655440020","type":"booking.created","occurredAt":"2026-07-24T12:00:00.000Z","businessId":"550e8400-e29b-41d4-a716-446655440002","subject":{"type":"booking","id":"550e8400-e29b-41d4-a716-446655440005"},"actor":{"type":"customer","id":"550e8400-e29b-41d4-a716-446655440001","name":null},"data":{"partySize":1}}}},"EventEnvelope":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"type":{"type":"string"},"occurredAt":{"$ref":"#/components/schemas/Timestamp"},"businessId":{"$ref":"#/components/schemas/Uuid"},"subject":{"type":"object","properties":{"type":{"type":"string"},"id":{"$ref":"#/components/schemas/Uuid"}},"required":["type","id"],"additionalProperties":false},"actor":{"type":"object","properties":{"type":{"type":"string","enum":["customer","user","system"]},"id":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["type","id","name"],"additionalProperties":false},"data":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["id","type","occurredAt","businessId","subject","actor","data"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440020","type":"booking.created","occurredAt":"2026-07-24T12:00:00.000Z","businessId":"550e8400-e29b-41d4-a716-446655440002","subject":{"type":"booking","id":"550e8400-e29b-41d4-a716-446655440005"},"actor":{"type":"customer","id":"550e8400-e29b-41d4-a716-446655440001","name":null},"data":{"partySize":1}}},"ScheduledTask":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"type":{"type":"string"},"subjectType":{"type":"string"},"subjectId":{"$ref":"#/components/schemas/Uuid"},"runAt":{"$ref":"#/components/schemas/Timestamp"},"status":{"type":"string"},"attempts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxAttempts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastError":{"anyOf":[{"type":"string"},{"type":"null"}]},"result":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","type","subjectType","subjectId","runAt","status","attempts","maxAttempts","lastError","result","payload","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440021","businessId":"550e8400-e29b-41d4-a716-446655440002","type":"booking.hold_expiry","subjectType":"booking","subjectId":"550e8400-e29b-41d4-a716-446655440005","runAt":"2026-08-01T18:00:00.000Z","status":"pending","attempts":0,"maxAttempts":5,"lastError":null,"result":null,"payload":{},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"TeamMember":{"type":"object","properties":{"userRole":{"$ref":"#/components/schemas/UserRole"},"person":{"$ref":"#/components/schemas/Person"},"instructorProfile":{"anyOf":[{"$ref":"#/components/schemas/InstructorProfile"},{"type":"null"}]},"hasPin":{"type":"boolean","description":"Holds a terminal PIN in this business. The PIN itself is shown once, when issued."},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"This business’s contact mobile for them: the one set on their team row here, else the mobile on their own account. Team writes never change the person’s own record."}},"required":["userRole","person","instructorProfile","hasPin","phone"],"additionalProperties":false,"example":{"userRole":{"id":"550e8400-e29b-41d4-a716-446655440015","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"roles":["owner"],"featureOverrides":{"grant":["booking.manage"],"revoke":[]},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null},"person":{"id":"550e8400-e29b-41d4-a716-446655440001","displayName":"Alex Rivera","legalGivenName":"Alex","legalFamilyName":"Rivera","email":"alex@example.com","phone":"+15551234567","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"},"instructorProfile":null,"hasPin":false,"phone":null}},"UserRole":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"personId":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"roles":{"type":"array","items":{"type":"string"}},"featureOverrides":{"$ref":"#/components/schemas/FeatureOverridesOutput"},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","personId","businessId","locationId","roles","featureOverrides","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440015","personId":"550e8400-e29b-41d4-a716-446655440001","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":null,"roles":["owner"],"featureOverrides":{"grant":["booking.manage"],"revoke":[]},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"EffectiveAccess":{"type":"object","properties":{"businessEnabled":{"type":"array","items":{"type":"string"}},"userGranted":{"type":"array","items":{"type":"string"}},"effective":{"type":"array","items":{"type":"string"}}},"required":["businessEnabled","userGranted","effective"],"additionalProperties":false,"example":{"businessEnabled":["booking.view","booking.manage"],"userGranted":["booking.manage"],"effective":["booking.view","booking.manage"]}},"TeamInviteResult":{"type":"object","properties":{"sent":{"type":"boolean"}},"required":["sent"],"additionalProperties":false,"example":{"sent":true}},"WaitlistEntry":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"type":"string"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"$ref":"#/components/schemas/Uuid"},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["waiting","offered","converted","expired","canceled"]},"offeredBookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","occurrenceId","offeringId","customerId","partySize","status","offeredBookingId","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440016","businessId":"550e8400-e29b-41d4-a716-446655440002","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","offeringId":"550e8400-e29b-41d4-a716-446655440004","customerId":"550e8400-e29b-41d4-a716-446655440006","partySize":1,"status":"waiting","offeredBookingId":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}},"ProcessExpiredWaitlistResult":{"type":"object","properties":{"processed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"promoted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["processed","promoted"],"additionalProperties":false,"example":{"processed":2,"promoted":1}},"MeCustomerRelationship":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"contact":{"$ref":"#/components/schemas/CustomerContact"},"hasAccount":{"type":"boolean"},"linkSource":{"anyOf":[{"type":"string","enum":["signin","checkout","waitlist","membership","backfill"]},{"type":"null"}]},"marketingConsent":{"type":"boolean"},"consentUpdatedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"consentSource":{"anyOf":[{"type":"string","enum":["checkout","preferences","unsubscribe","admin","import","merge"]},{"type":"null"}]},"stats":{"$ref":"#/components/schemas/CustomerDerivedStats"},"business":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"locale":{"$ref":"#/components/schemas/Locale"},"dateFormat":{"$ref":"#/components/schemas/DateFormat"},"bookingMessages":{"type":"string","enum":["email","sms"]}},"required":["id","name","slug","locale","dateFormat","bookingMessages"],"additionalProperties":false,"description":"The studio’s public face and the two settings the account page reads — never its operator record (accountant, payments account, fee mode)."},"smsConsentPhone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The number this person ticked the SMS box for at this studio, or null (build-plan/178). Texts go only while it equals contact.phone."},"studioCardWalletLinks":{"description":"Add to Apple / Google Wallet for this person’s studio card here (build-plan/262): capability links, each null while that wallet is off. Absent while both are off.","type":"object","properties":{"apple":{"anyOf":[{"type":"string"},{"type":"null"}]},"google":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["apple","google"],"additionalProperties":false}},"required":["id","businessId","contact","hasAccount","linkSource","marketingConsent","consentUpdatedAt","consentSource","stats","business","smsConsentPhone"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440006","businessId":"550e8400-e29b-41d4-a716-446655440002","contact":{"email":"alex@example.com","phone":"+15551234567","givenName":"Alex","familyName":"Rivera","displayName":"Alex Rivera"},"hasAccount":true,"linkSource":"checkout","marketingConsent":true,"consentUpdatedAt":"2026-07-24T12:00:00.000Z","consentSource":"checkout","stats":{"firstSeenAt":"2026-07-24T12:00:00.000Z","lastSeenAt":"2026-07-24T12:00:00.000Z","lastBookingStartAt":"2026-07-24T12:00:00.000Z","nextBookingStartAt":"2026-08-01T18:00:00.000Z","bookingsCount":12,"canceledCount":1,"noShowCount":0,"lifetimeSpendAmount":36000,"lifetimeSpendCurrency":"USD","activeMemberships":1},"business":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","slug":"sunrise-studio","locale":"en-US","dateFormat":"MDY","bookingMessages":"email"},"smsConsentPhone":null}},"MeBookingsResult":{"type":"object","properties":{"upcoming":{"type":"array","items":{"$ref":"#/components/schemas/MeBooking"}},"past":{"type":"array","items":{"$ref":"#/components/schemas/MeBooking"}},"pastHasMore":{"type":"boolean"}},"required":["upcoming","past","pastHasMore"],"additionalProperties":false,"example":{"upcoming":[{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[],"businessName":"Sunrise Studio","locationName":"Downtown Studio","locationTimezone":"America/Denver","offeringName":"Morning Flow","listingSlug":"morning-flow","occurrenceStartsAt":"2026-08-01T18:00:00.000Z","occurrenceEndsAt":"2026-08-01T19:00:00.000Z"}],"past":[],"pastHasMore":false}},"MeBooking":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"$ref":"#/components/schemas/Uuid"},"occurrenceId":{"type":"string"},"enrollmentId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"subscriptionMembershipId":{"description":"A subscription's session (build-plan/280): the subscription it belongs to.","anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookedBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"channel":{"type":"string","enum":["online","staff","api"]},"source":{"anyOf":[{"type":"string","enum":["page","embed","embed_schedule","desk","agent","api","import"]},{"type":"null"}],"description":"Where this booking came from (architecture/06 § source): page | embed | embed_schedule | desk | agent | api | import (Bookings → Import, build-plan/285). Null predates this column, or a waitlist promotion, and reads Unknown — there is no backfill."},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["held","confirmed","checked_in","checked_out","completed","canceled","no_show"]},"checkedInAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"checkedOutAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"completedAt":{"description":"Set when the journey's Complete ran (architecture/06 § 5). After it, only refunds and payments change the booking.","anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"holdExpiresAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"priceSnapshot":{"$ref":"#/components/schemas/BookingQuote"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"appliedMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"creditsApplied":{"$ref":"#/components/schemas/MoneyAmount"},"platformFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"customerFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"taxAmount":{"$ref":"#/components/schemas/MoneyAmount"},"feeBpsSnapshot":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"feeModeSnapshot":{"anyOf":[{"type":"string","enum":["absorb","split","pass"]},{"type":"null"}]},"cancellationReason":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"reference":{"type":"string"},"paidElsewhere":{"description":"Paid through another system — Groupon, the POS (architecture/24 § Paid elsewhere, § Closing out). Nothing is owed here for it and the ledger never sees it.","anyOf":[{"type":"object","properties":{"channelId":{"$ref":"#/components/schemas/Uuid"},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"label":{"type":"string"},"amount":{"description":"What was closed out through the method after booking (a balance); 0 when the whole line was paid elsewhere from the hold.","$ref":"#/components/schemas/MoneyAmount"}},"required":["channelId","reference","label"],"additionalProperties":false},{"type":"null"}]},"note":{"description":"The note the import wrote (build-plan/285 D11): the file’s Notes columns, one line each (Label: VIP). Null with none.","anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"amountPaid":{"$ref":"#/components/schemas/MoneyAmount"},"amountDue":{"$ref":"#/components/schemas/MoneyAmount"},"positions":{"type":"array","items":{"$ref":"#/components/schemas/BookingAssignedPosition"}},"closedBy":{"description":"Detail read only (build-plan/249): the closure over this booking, in the Calendar's words (Closed · block). Null when the time is open. Computed at read time; there is no column. Absent on a list.","anyOf":[{"type":"string"},{"type":"null"}]},"checkOutReleasesSpace":{"description":"Detail read only (build-plan/250): this booking is its date's only seat-holder and the date has not ended, so checking out ends the held window now and frees the room or table. Absent on a list.","type":"boolean"},"businessName":{"type":"string"},"locationName":{"type":"string"},"locationTimezone":{"type":"string"},"offeringName":{"type":"string"},"listingSlug":{"type":"string"},"occurrenceStartsAt":{"$ref":"#/components/schemas/Timestamp"},"occurrenceEndsAt":{"$ref":"#/components/schemas/Timestamp"},"seriesName":{"anyOf":[{"type":"string"},{"type":"null"}]},"piecesReady":{"description":"Pieces on Ready, waiting to be picked up (build-plan/277); absent when none are.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","businessId","locationId","offeringId","occurrenceId","customerId","bookedBy","cartId","channel","source","partySize","status","holdExpiresAt","priceSnapshot","amountTotal","currency","appliedMembershipId","creditMembershipId","creditsApplied","platformFeeAmount","customerFeeAmount","feeBpsSnapshot","feeModeSnapshot","cancellationReason","idempotencyKey","reference","createdAt","updatedAt","amountPaid","amountDue","businessName","locationName","locationTimezone","offeringName","listingSlug","occurrenceStartsAt","occurrenceEndsAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440005","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","offeringId":"550e8400-e29b-41d4-a716-446655440004","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","enrollmentId":null,"customerId":"550e8400-e29b-41d4-a716-446655440006","bookedBy":"550e8400-e29b-41d4-a716-446655440001","cartId":"550e8400-e29b-41d4-a716-446655440022","channel":"online","source":"page","partySize":1,"status":"held","holdExpiresAt":"2026-08-01T18:00:00.000Z","priceSnapshot":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"amountTotal":3000,"currency":"USD","appliedMembershipId":null,"creditMembershipId":null,"creditsApplied":0,"platformFeeAmount":60,"customerFeeAmount":0,"feeBpsSnapshot":200,"feeModeSnapshot":"absorb","cancellationReason":null,"idempotencyKey":null,"reference":"BK-00000001","paidElsewhere":null,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","amountPaid":0,"amountDue":3000,"positions":[],"businessName":"Sunrise Studio","locationName":"Downtown Studio","locationTimezone":"America/Denver","offeringName":"Morning Flow","listingSlug":"morning-flow","occurrenceStartsAt":"2026-08-01T18:00:00.000Z","occurrenceEndsAt":"2026-08-01T19:00:00.000Z"}},"MeMembershipsResult":{"type":"object","properties":{"memberships":{"type":"array","items":{"$ref":"#/components/schemas/MeMembership"}}},"required":["memberships"],"additionalProperties":false,"example":{"memberships":[{"id":"550e8400-e29b-41d4-a716-446655440011","businessId":"550e8400-e29b-41d4-a716-446655440002","businessName":"Sunrise Studio","customerId":"550e8400-e29b-41d4-a716-446655440006","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","planName":"Unlimited Monthly","billingPeriod":"monthly","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","creditsRemaining":500,"benefits":[{"type":"credit","config":{"amount":10,"period":"monthly","scope":"all","rollover":false}}],"ownedCardSvg":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 428 270\" width=\"640\" height=\"404\" role=\"img\" aria-label=\"Unlimited Monthly: Jordan Lee, 5 credits left\">…</svg>","walletLinks":{"apple":null,"google":null}}]}},"MeMembership":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"businessName":{"type":"string"},"customerId":{"$ref":"#/components/schemas/Uuid"},"membershipPlanId":{"$ref":"#/components/schemas/Uuid"},"planName":{"type":"string"},"billingPeriod":{"type":"string","enum":["none","one_time","weekly","monthly","yearly"]},"status":{"type":"string","enum":["active","past_due","paused","canceled","expired"]},"startedAt":{"$ref":"#/components/schemas/Timestamp"},"currentPeriodEnd":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"creditsRemaining":{"$ref":"#/components/schemas/MoneyAmount"},"benefits":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type","config"],"additionalProperties":false}},"ownedCardSvg":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The owned card as inline SVG, drawn for this holder at request time and never stored. Null while the plan has no card design."},"walletLinks":{"anyOf":[{"type":"object","properties":{"apple":{"anyOf":[{"type":"string"},{"type":"null"}]},"google":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["apple","google"],"additionalProperties":false},{"type":"null"}],"description":"Add to Apple Wallet and Add to Google Wallet links for this holder, shown beneath the card: capability URLs with the token in the path. Each is null while that wallet is off; both are null once the membership has ended. Null with no owned card."},"subscription":{"description":"A subscription to a listing (build-plan/280): its listing, spots, weekly time, term charge and card. Null on a pass or membership.","anyOf":[{"type":"object","properties":{"listingName":{"type":"string"},"listingSlug":{"type":"string"},"locationSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"timezone":{"type":"string"},"spots":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"whenLabel":{"type":"string","description":"\"Wednesdays 3:30 pm\" (one time a week) or \"Every session\""},"term":{"type":"string","enum":["weekly","monthly"]},"amount":{"description":"A term's charge before tax: price per spot × spots − the discount it kept","$ref":"#/components/schemas/MoneyAmount"},"currency":{"type":"string"},"cardLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"nextAttemptAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"Past due: when the next try is"},"billingMode":{"type":"string","enum":["card","manual"],"description":"card: it renews on the card on file, and the holder can change its spots from its page; manual: the studio records each term"}},"required":["listingName","listingSlug","locationSlug","timezone","spots","whenLabel","term","amount","currency","cardLabel","nextAttemptAt","billingMode"],"additionalProperties":false},{"type":"null"}]}},"required":["id","businessId","businessName","customerId","membershipPlanId","planName","billingPeriod","status","startedAt","currentPeriodEnd","creditsRemaining","benefits","ownedCardSvg","walletLinks"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440011","businessId":"550e8400-e29b-41d4-a716-446655440002","businessName":"Sunrise Studio","customerId":"550e8400-e29b-41d4-a716-446655440006","membershipPlanId":"550e8400-e29b-41d4-a716-446655440010","planName":"Unlimited Monthly","billingPeriod":"monthly","status":"active","startedAt":"2026-07-24T12:00:00.000Z","currentPeriodEnd":"2026-08-01T18:00:00.000Z","creditsRemaining":500,"benefits":[{"type":"credit","config":{"amount":10,"period":"monthly","scope":"all","rollover":false}}],"ownedCardSvg":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 428 270\" width=\"640\" height=\"404\" role=\"img\" aria-label=\"Unlimited Monthly: Jordan Lee, 5 credits left\">…</svg>","walletLinks":{"apple":null,"google":null}}},"MeListingSubscriptionsResult":{"type":"object","properties":{"subscriptions":{"type":"array","items":{"type":"object","properties":{"membershipId":{"$ref":"#/components/schemas/Uuid"},"weekday":{"anyOf":[{"type":"integer","minimum":1,"maximum":7},{"type":"null"}]},"startMinute":{"anyOf":[{"type":"integer","minimum":0,"maximum":1439},{"type":"null"}]}},"required":["membershipId","weekday","startMinute"],"additionalProperties":false}},"waiting":{"type":"array","items":{"type":"object","properties":{"weekday":{"anyOf":[{"type":"integer","minimum":1,"maximum":7},{"type":"null"}]},"startMinute":{"anyOf":[{"type":"integer","minimum":0,"maximum":1439},{"type":"null"}]},"whenLabel":{"type":"string"},"position":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"spots":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"status":{"type":"string","enum":["waiting","offered"],"description":"offered: a spot is held for them and the link is in their email"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"leaveToken":{"type":"string","description":"Takes this place off the line: POST /storefront/waitlist/leave, no session needed."}},"required":["weekday","startMinute","whenLabel","position","spots","status","email","leaveToken"],"additionalProperties":false},"description":"My places in this listing's waitlist, so its page says I'm on the list where Join waitlist was."}},"required":["subscriptions","waiting"],"additionalProperties":false,"example":{"subscriptions":[{"membershipId":"01a14616-8a86-71df-ba97-32c72aa40da9","weekday":4,"startMinute":780}],"waiting":[{"weekday":2,"startMinute":1080,"whenLabel":"Tuesdays 6:00 pm","position":1,"spots":1,"status":"waiting","email":"sam.lee@example.com","leaveToken":"MDFhMTQ2MTY.k3J9xQ2mVZ4pL8wR7tYb1A"}]}},"StorefrontBusinessProfile":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"url":{"anyOf":[{"type":"string"},{"type":"null"}]},"locations":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"address":{"type":"string"},"timezone":{"type":"string"}},"required":["id","name","slug","address","timezone"],"additionalProperties":false}}},"required":["id","name","description","url","locations"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440002","name":"Sunrise Studio","description":"Yoga and pilates in Denver","url":"https://sunrise.example.com","locations":[{"id":"550e8400-e29b-41d4-a716-446655440003","name":"Downtown Studio","slug":"sunrise-studio","address":"123 Main St, Denver, CO","timezone":"America/Denver"}]}},"StorefrontLocationProfile":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"type":"string"},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"timezone":{"type":"string"},"hours":{"type":"object","properties":{"timezone":{"type":"string"},"schedule":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"rrule":{"type":"string"},"timezone":{"type":"string"}},"required":["name","rrule","timezone"],"additionalProperties":false},{"type":"null"}]}},"required":["timezone","schedule"],"additionalProperties":false}},"required":["id","businessId","name","description","address","lat","lng","timezone","hours"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440003","businessId":"550e8400-e29b-41d4-a716-446655440002","name":"Downtown Studio","description":"Main street location","address":"123 Main St, Denver, CO","lat":39.7392,"lng":-104.9903,"timezone":"America/Denver","hours":{"timezone":"America/Denver","schedule":{"name":"Regular hours","rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","timezone":"America/Denver"}}}},"StorefrontPaginatedListings":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StorefrontListingSummary"}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["items","nextCursor"],"additionalProperties":false,"example":{"items":[{"id":"550e8400-e29b-41d4-a716-446655440004","name":"Morning Flow","slug":"morning-flow","description":"All-levels vinyasa","type":"class","priceAmount":3000,"priceCurrency":"USD","image":{"url":"https://cdn.example.com/class.jpg","sortOrder":0,"altText":null}}],"nextCursor":null}},"StorefrontListingSummary":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":{"type":"string"},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"$ref":"#/components/schemas/Currency"},"image":{"anyOf":[{"type":"object","properties":{"url":{"type":"string"},"sortOrder":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"altText":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["url","sortOrder"],"additionalProperties":false},{"type":"null"}]}},"required":["id","name","slug","description","type","priceAmount","priceCurrency","image"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440004","name":"Morning Flow","slug":"morning-flow","description":"All-levels vinyasa","type":"class","priceAmount":3000,"priceCurrency":"USD","image":{"url":"https://cdn.example.com/class.jpg","sortOrder":0,"altText":null}}},"StorefrontListingDetail":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"type":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"$ref":"#/components/schemas/Currency"},"depositType":{"type":"string"},"depositAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}]},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"durationMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"slotGranularityMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bookingHorizonDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingCutoffMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cancellationCutoffHours":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"sortOrder":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"altText":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["url","sortOrder"],"additionalProperties":false}},"schedules":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"timezone":{"type":"string"},"rrule":{"type":"string"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","name","timezone","rrule","durationMinutes"],"additionalProperties":false}},"instructors":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"bio":{"type":"string"},"headshotUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"specialties":{"type":"array","items":{"type":"string"}}},"required":["id","bio","headshotUrl","specialties"],"additionalProperties":false}},"addOns":{"type":"array","items":{"$ref":"#/components/schemas/StorefrontAddOn"},"description":"For-sale products offered with this listing. `available` is a boolean, never a count."}},"required":["id","locationId","type","name","slug","description","priceAmount","priceCurrency","depositType","depositAmount","capacity","durationMinutes","slotGranularityMinutes","bookingHorizonDays","bookingCutoffMinutes","cancellationCutoffHours","images","schedules","instructors","addOns"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440004","locationId":"550e8400-e29b-41d4-a716-446655440003","type":"class","name":"Morning Flow","slug":"morning-flow","description":"All-levels vinyasa","priceAmount":3000,"priceCurrency":"USD","depositType":"percent","depositAmount":50,"capacity":20,"durationMinutes":60,"slotGranularityMinutes":null,"bookingHorizonDays":30,"bookingCutoffMinutes":60,"cancellationCutoffHours":24,"images":[{"url":"https://cdn.example.com/class.jpg","sortOrder":0,"altText":null}],"schedules":[{"id":"550e8400-e29b-41d4-a716-446655440014","name":"Weekday mornings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","durationMinutes":60}],"instructors":[{"id":"550e8400-e29b-41d4-a716-446655440008","bio":"RYT-200","headshotUrl":null,"specialties":["vinyasa"]}],"addOns":[{"productId":"550e8400-e29b-41d4-a716-446655440027","name":"Bisque piece","required":true,"maxPerSpot":null,"variants":[{"variantId":"550e8400-e29b-41d4-a716-446655440028","name":"Mug","priceAmount":1200,"available":true,"lastOne":false}]}]}},"StorefrontAddOn":{"type":"object","properties":{"productId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"required":{"type":"boolean"},"maxPerSpot":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"variants":{"type":"array","items":{"type":"object","properties":{"variantId":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"available":{"type":"boolean"},"lastOne":{"type":"boolean"}},"required":["variantId","name","priceAmount","available","lastOne"],"additionalProperties":false}}},"required":["productId","name","required","maxPerSpot","variants"],"additionalProperties":false,"example":{"productId":"550e8400-e29b-41d4-a716-446655440027","name":"Bisque piece","required":true,"maxPerSpot":null,"variants":[{"variantId":"550e8400-e29b-41d4-a716-446655440028","name":"Mug","priceAmount":1200,"available":true,"lastOne":false}]}},"StorefrontSeries":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"displayName":{"type":"string"},"startsAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"endsAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"occurrences":{"type":"array","items":{"type":"object","properties":{"occurrenceId":{"$ref":"#/components/schemas/Uuid"},"startsAt":{"type":"string"},"endsAt":{"type":"string"},"timezone":{"type":"string"}},"required":["occurrenceId","startsAt","endsAt","timezone"],"additionalProperties":false}},"sessionCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"displayedPriceAmount":{"$ref":"#/components/schemas/MoneyAmount"},"priceCurrency":{"$ref":"#/components/schemas/Currency"},"spotsRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"enrollmentOpen":{"type":"boolean"},"pricePerSession":{"$ref":"#/components/schemas/MoneyAmount"}},"required":["id","displayName","startsAt","endsAt","occurrences","sessionCount","displayedPriceAmount","priceCurrency","spotsRemaining","enrollmentOpen","pricePerSession"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440024","displayName":"Sep 15 – Oct 20","startsAt":"2026-09-15T18:00:00.000Z","endsAt":"2026-10-20T20:00:00.000Z","occurrences":[],"sessionCount":6,"displayedPriceAmount":24000,"priceCurrency":"USD","spotsRemaining":8,"enrollmentOpen":true,"pricePerSession":4000}},"StorefrontAvailability":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"slots":{"type":"array","items":{"$ref":"#/components/schemas/OccurrenceSlot"}}},"required":["offeringId","locationId","slots"],"additionalProperties":false,"example":{"offeringId":"550e8400-e29b-41d4-a716-446655440004","locationId":"550e8400-e29b-41d4-a716-446655440003","slots":[{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","localStart":"2026-08-01T12:00:00","localEnd":"2026-08-01T13:00:00","timezone":"America/Denver","capacityTotal":20,"capacityRemaining":5,"maxPartySize":null,"capacityByStatus":{"held":0,"confirmed":5,"completed":0,"noShow":0,"elsewhere":0},"status":"open","materialized":false,"instructorIds":[]}]}},"StorefrontQuoteResult":{"type":"object","properties":{"quote":{"$ref":"#/components/schemas/BookingQuote"},"availability":{"anyOf":[{"type":"object","properties":{"available":{"type":"boolean"},"capacityRemaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"status":{"type":"string","enum":["open","full","blacked_out","closed"]}},"required":["available","capacityRemaining","status"],"additionalProperties":false},{"type":"null"}]},"creditsApplied":{"$ref":"#/components/schemas/MoneyAmount"},"creditRedemptionAvailable":{"type":"boolean"},"appliedMembershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"accessAllowed":{"type":"boolean"},"memberOffer":{"anyOf":[{"$ref":"#/components/schemas/StorefrontMemberOffer"},{"type":"null"}]},"discount":{"anyOf":[{"$ref":"#/components/schemas/StorefrontQuoteDiscount"},{"type":"null"}],"description":"The automatic discount this booking wins on its own, with a time chosen — the row the quote carries, so the page says it above Book. Null when none applies, no time is chosen, or a membership benefit beat it. A code is never applied here; the cart runs every line together and can only match or beat this."}},"required":["quote","availability","creditsApplied","creditRedemptionAvailable","appliedMembershipId","accessAllowed","memberOffer","discount"],"additionalProperties":false,"example":{"quote":{"base":3000,"currency":"USD","partySize":1,"adjustments":[],"discountedSubtotal":3000,"creditsApplied":0,"amountDueTotal":3000,"amountDueNow":1500,"amountDueLater":1500,"creditRedemptionAvailable":false,"appliedMembershipId":null,"creditMembershipId":null,"platformFeeAmount":60,"customerFeeAmount":0,"feeBps":200,"feeMode":"absorb","taxTotal":0,"taxNow":0,"taxLater":0,"taxes":[]},"availability":{"available":true,"capacityRemaining":5,"status":"open"},"creditsApplied":0,"creditRedemptionAvailable":false,"appliedMembershipId":null,"accessAllowed":true,"memberOffer":null,"discount":null}},"StorefrontQuoteDiscount":{"type":"object","properties":{"discountId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string","description":"The discount's name, as the receipt will show it."},"amount":{"description":"What it takes off this booking, minor units, positive.","$ref":"#/components/schemas/MoneyAmount"}},"required":["discountId","name","amount"],"additionalProperties":false,"example":{"discountId":"550e8400-e29b-41d4-a716-446655440030","name":"Siblings: half price after two","amount":4000}},"StorefrontWaitlistJoinResult":{"type":"object","properties":{"status":{"type":"string"},"position":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"alreadyJoined":{"type":"boolean"},"email":{"type":"string"},"spots":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"leaveToken":{"type":"string","description":"Takes this place off the line: POST /storefront/waitlist/leave, no session needed."}},"required":["status","position","alreadyJoined","email","spots","leaveToken"],"additionalProperties":false,"example":{"status":"waiting","position":2,"alreadyJoined":false,"email":"sam.lee@example.com","spots":2,"leaveToken":"MDFhMTQ2MTY.k3J9xQ2mVZ4pL8wR7tYb1A"}},"StorefrontSubscriptionWaitlistJoinResult":{"type":"object","properties":{"status":{"type":"string"},"position":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"alreadyJoined":{"type":"boolean"},"whenLabel":{"type":"string"},"email":{"type":"string"},"spots":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"leaveToken":{"type":"string","description":"Takes this place off the line: POST /storefront/waitlist/leave, no session needed."}},"required":["status","position","alreadyJoined","whenLabel","email","spots","leaveToken"],"additionalProperties":false,"example":{"status":"waiting","position":1,"alreadyJoined":false,"whenLabel":"Thursdays 1:00 pm","email":"sam.lee@example.com","spots":1,"leaveToken":"MDFhMTQ2MTY.k3J9xQ2mVZ4pL8wR7tYb1A"}},"StorefrontWaitlistLeaveResult":{"type":"object","properties":{"left":{"type":"boolean"},"status":{"type":"string"}},"required":["left","status"],"additionalProperties":false,"example":{"left":true,"status":"canceled"}},"Cart":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"token":{"type":"string"},"businessId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["open","checked_out","canceled"]},"channel":{"type":"string","enum":["online","staff","api"]},"createdBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"currency":{"$ref":"#/components/schemas/Currency"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerFirstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"checkedOutAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CartItem"}},"amountDueNow":{"$ref":"#/components/schemas/MoneyAmount"},"amountDueLater":{"$ref":"#/components/schemas/MoneyAmount"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"amountTax":{"$ref":"#/components/schemas/MoneyAmount"},"amountCustomerFee":{"$ref":"#/components/schemas/MoneyAmount"},"feeLabel":{"type":"string","enum":["booking","service"],"description":"The fee row reads \"Booking fee\" (`booking`) when any booking or series item is in the cart, \"Service fee\" (`service`) otherwise."},"agreements":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"$ref":"#/components/schemas/Uuid"},"ask":{"type":"string","enum":["checkbox","must_read"]}},"required":["id","name","kind","path","contentId","ask"],"additionalProperties":false}},"agreementsAgreed":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"$ref":"#/components/schemas/Uuid"},"ask":{"type":"string","enum":["checkbox","must_read"]}},"required":["id","name","kind","path","contentId","ask"],"additionalProperties":false}},"memberOffer":{"anyOf":[{"$ref":"#/components/schemas/StorefrontMemberOffer"},{"type":"null"}]},"discountCode":{"anyOf":[{"type":"object","properties":{"code":{"type":"string"},"state":{"type":"string","enum":["applied","no_match"]},"amount":{"$ref":"#/components/schemas/MoneyAmount"}},"required":["code","state","amount"],"additionalProperties":false},{"type":"null"}]}},"required":["id","token","businessId","status","channel","createdBy","currency","note","customerFirstName","checkedOutAt","createdAt","items","amountDueNow","amountDueLater","amountTotal","amountCustomerFee","feeLabel"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440022","token":"wS3nQ8xKf1JqL7ZtB4gYcR2v","businessId":"550e8400-e29b-41d4-a716-446655440002","status":"open","createdBy":null,"channel":"online","currency":"USD","note":null,"customerFirstName":null,"checkedOutAt":null,"createdAt":"2026-07-24T12:00:00.000Z","items":[{"id":"550e8400-e29b-41d4-a716-446655440023","itemType":"booking","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipPlanId":null,"membershipId":null,"state":"held","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Beginner Wheel Throwing","listingType":"class","listingSlug":"beginner-wheel-throwing","locationSlug":"riverbend-pottery","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T20:00:00.000Z","timezone":"America/Denver","partySize":1,"holdExpiresAt":"2026-08-01T18:00:00.000Z","cancellationCutoffHours":24,"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"taxAmount":0,"customerFeeAmount":0,"currency":"USD","taxes":[],"adjustments":[],"answers":[],"attendeeFirstName":null,"creditsApplied":0}],"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"amountTax":0,"amountCustomerFee":0,"feeLabel":"booking","memberOffer":null,"discountCode":null,"questions":[{"id":"550e8400-e29b-41d4-a716-446655440077","prompt":"Any wheel experience?","helpText":null,"type":"radio","options":["None","Some","Lots"],"required":true}]}},"AnswerSuggestions":{"type":"array","items":{"type":"object","properties":{"questionId":{"$ref":"#/components/schemas/Uuid"},"suggestions":{"type":"array","items":{"type":"object","properties":{"value":{"anyOf":[{"type":"string"},{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal":{"type":"string"},"country":{"type":"string"}},"required":["line1","line2","city","region","postal","country"],"additionalProperties":false}]},"lastAnsweredAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["value","lastAnsweredAt"],"additionalProperties":false}}},"required":["questionId","suggestions"],"additionalProperties":false},"example":[{"questionId":"550e8400-e29b-41d4-a716-446655440077","suggestions":[{"value":"Some","lastAnsweredAt":"2026-07-24T12:00:00.000Z"}]}]},"CartSettleResult":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"token":{"type":"string"},"businessId":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["open","checked_out","canceled"]},"channel":{"type":"string","enum":["online","staff","api"]},"createdBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"currency":{"$ref":"#/components/schemas/Currency"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerFirstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"checkedOutAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CartItem"}},"amountDueNow":{"$ref":"#/components/schemas/MoneyAmount"},"amountDueLater":{"$ref":"#/components/schemas/MoneyAmount"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"amountTax":{"$ref":"#/components/schemas/MoneyAmount"},"amountCustomerFee":{"$ref":"#/components/schemas/MoneyAmount"},"feeLabel":{"type":"string","enum":["booking","service"],"description":"The fee row reads \"Booking fee\" (`booking`) when any booking or series item is in the cart, \"Service fee\" (`service`) otherwise."},"agreements":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"$ref":"#/components/schemas/Uuid"},"ask":{"type":"string","enum":["checkbox","must_read"]}},"required":["id","name","kind","path","contentId","ask"],"additionalProperties":false}},"agreementsAgreed":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["text","pdf"]},"path":{"type":"string"},"contentId":{"$ref":"#/components/schemas/Uuid"},"ask":{"type":"string","enum":["checkbox","must_read"]}},"required":["id","name","kind","path","contentId","ask"],"additionalProperties":false}},"memberOffer":{"anyOf":[{"$ref":"#/components/schemas/StorefrontMemberOffer"},{"type":"null"}]},"discountCode":{"anyOf":[{"type":"object","properties":{"code":{"type":"string"},"state":{"type":"string","enum":["applied","no_match"]},"amount":{"$ref":"#/components/schemas/MoneyAmount"}},"required":["code","state","amount"],"additionalProperties":false},{"type":"null"}]},"payment":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"status":{"type":"string","enum":["requires_action","authorized","captured","canceled","failed","refunded","partially_refunded"],"description":"The attempt's status after the provider's record was read"},"decline":{"anyOf":[{"type":"object","properties":{"code":{"type":"string","description":"`card_declined` when the provider refused the card (its own code stays on the cart's `checkout_attempt` row — build-plan/279), or `not_charged` when a TRX sale whose answer was lost turned out never to have happened"},"message":{"type":"string","description":"The one sentence every refused card gets, *That card was declined. Try another card.*, or *Your card was not charged. Try again.* — never the provider's words"}},"required":["code","message"],"additionalProperties":false},{"type":"null"}],"description":"Why the attempt failed, when the provider said (TRX); Stripe declines in the browser and leaves this null"}},"required":["id","status","decline"],"additionalProperties":false},{"type":"null"}],"description":"The cart's live attempt and what the read made of it; null when the cart holds no live attempt (nothing was read)"}},"required":["id","token","businessId","status","channel","createdBy","currency","note","customerFirstName","checkedOutAt","createdAt","items","amountDueNow","amountDueLater","amountTotal","amountCustomerFee","feeLabel","payment"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440022","token":"wS3nQ8xKf1JqL7ZtB4gYcR2v","businessId":"550e8400-e29b-41d4-a716-446655440002","status":"open","createdBy":null,"channel":"online","currency":"USD","note":null,"customerFirstName":null,"checkedOutAt":null,"createdAt":"2026-07-24T12:00:00.000Z","items":[{"id":"550e8400-e29b-41d4-a716-446655440023","itemType":"booking","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipPlanId":null,"membershipId":null,"state":"held","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Beginner Wheel Throwing","listingType":"class","listingSlug":"beginner-wheel-throwing","locationSlug":"riverbend-pottery","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T20:00:00.000Z","timezone":"America/Denver","partySize":1,"holdExpiresAt":"2026-08-01T18:00:00.000Z","cancellationCutoffHours":24,"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"taxAmount":0,"customerFeeAmount":0,"currency":"USD","taxes":[],"adjustments":[],"answers":[],"attendeeFirstName":null,"creditsApplied":0}],"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"amountTax":0,"amountCustomerFee":0,"feeLabel":"booking","memberOffer":null,"discountCode":null,"questions":[{"id":"550e8400-e29b-41d4-a716-446655440077","prompt":"Any wheel experience?","helpText":null,"type":"radio","options":["None","Some","Lots"],"required":true}],"payment":null}},"CardSession":{"type":"object","properties":{"provider":{"type":"string","const":"trx"},"scriptUrl":{"type":"string","format":"uri","description":"TRX's card-fields script for the gateway in force (`window.PayPageJS`): `paypage-fields.trxservices.net/bundle.js` on the test gateway, `.com` on live."},"clientId":{"type":"string","description":"The merchant's TRX client id — `sessionData.clientId`."},"sessionId":{"type":"string","description":"TRX's token for this one session — `sessionData.sessionId`. A new one on every call."},"payPageId":{"type":"string","description":"The merchant's page configuration — `sessionData.payPageId`. The same on every session."},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When the session ends (30 minutes). The encrypted card the fields hand back is itself good for 15 minutes."},"wallets":{"description":"Only on a wallet session (`{ wallets: true }` where wallets are offered; build-plan/213 ticket 1.4): the wallet buttons this session allows. Absent, the answer is exactly a card session's.","type":"object","properties":{"applePay":{"type":"boolean"},"googlePay":{"type":"boolean"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The amount the session was opened for, in minor units — the total Apple Pay's and Google Pay's sheets show. The page mounts the buttons only while its own button shows the same."}},"required":["applePay","googlePay","amount"],"additionalProperties":false}},"required":["provider","scriptUrl","clientId","sessionId","payPageId","expiresAt"],"additionalProperties":false,"example":{"provider":"trx","scriptUrl":"https://paypage-fields.trxservices.net/bundle.js","clientId":"412","sessionId":"sess-1","payPageId":"PP0000000001","expiresAt":"2026-10-01T18:30:00.000Z"}},"CheckoutResult":{"type":"object","properties":{"cart":{"$ref":"#/components/schemas/Cart"},"payment":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"membershipId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"provider":{"type":"string","enum":["stripe","manual","trx"]},"providerRef":{"anyOf":[{"type":"string"},{"type":"null"}]},"connectedAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"applicationFeeAmount":{"$ref":"#/components/schemas/MoneyAmount"},"amount":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"purpose":{"type":"string","enum":["booking_deposit","booking_balance","booking_full","membership","open","cart"]},"status":{"type":"string","enum":["requires_action","authorized","captured","canceled","failed","refunded","partially_refunded"]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"clientSecret":{"description":"What the browser needs to take the card, by `provider` — the business's card provider, never the page's choice (build-plan/200). `stripe`: the PaymentIntent client secret, confirmed with Stripe.js on `connectedAccountId`. `trx`: absent (`connectedAccountId` is null) — the card arrives in the request as `card` and is charged inside it, so the cart comes back `checked_out` and the payment `captured`. Absent for `manual`, which settles at once.","type":"string"}},"required":["id","businessId","customerId","bookingId","membershipId","cartId","provider","providerRef","connectedAccountId","applicationFeeAmount","amount","currency","purpose","status","createdAt","updatedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["cart","payment"],"additionalProperties":false,"example":{"cart":{"id":"550e8400-e29b-41d4-a716-446655440022","token":"wS3nQ8xKf1JqL7ZtB4gYcR2v","businessId":"550e8400-e29b-41d4-a716-446655440002","status":"checked_out","createdBy":null,"channel":"online","currency":"USD","note":null,"customerFirstName":null,"checkedOutAt":"2026-07-24T12:00:00.000Z","createdAt":"2026-07-24T12:00:00.000Z","items":[{"id":"550e8400-e29b-41d4-a716-446655440023","itemType":"booking","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipPlanId":null,"membershipId":null,"state":"held","offeringId":"550e8400-e29b-41d4-a716-446655440004","offeringName":"Beginner Wheel Throwing","listingType":"class","listingSlug":"beginner-wheel-throwing","locationSlug":"riverbend-pottery","occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T20:00:00.000Z","timezone":"America/Denver","partySize":1,"holdExpiresAt":"2026-08-01T18:00:00.000Z","cancellationCutoffHours":24,"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"taxAmount":0,"customerFeeAmount":0,"currency":"USD","taxes":[],"adjustments":[],"answers":[],"attendeeFirstName":null,"creditsApplied":0}],"amountDueNow":3000,"amountDueLater":0,"amountTotal":3000,"amountTax":0,"amountCustomerFee":0,"feeLabel":"booking","memberOffer":null,"discountCode":null,"questions":[{"id":"550e8400-e29b-41d4-a716-446655440077","prompt":"Any wheel experience?","helpText":null,"type":"radio","options":["None","Some","Lots"],"required":true}]},"payment":{"id":"550e8400-e29b-41d4-a716-446655440009","businessId":"550e8400-e29b-41d4-a716-446655440002","customerId":"550e8400-e29b-41d4-a716-446655440006","bookingId":"550e8400-e29b-41d4-a716-446655440005","membershipId":null,"cartId":null,"provider":"stripe","providerRef":"pi_123","connectedAccountId":"acct_123","applicationFeeAmount":150,"amount":3000,"currency":"USD","purpose":"booking_deposit","status":"authorized","createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z"}}},"ManageBooking":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"reference":{"type":"string"},"status":{"type":"string","enum":["held","confirmed","checked_in","checked_out","completed","canceled","no_show"]},"listing":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"slug":{"type":"string"},"type":{"type":"string"},"capacity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bookingHorizonDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"spotsLeft":{"type":"string","enum":["few","always"],"description":"Effective Spots left — when a time in the move picker says \"N spots left\" (build-plan/238)."},"confirmationMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"meetingUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"meetingInstructions":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","slug","type","capacity","bookingHorizonDays","spotsLeft","confirmationMessage","meetingUrl","meetingInstructions"],"additionalProperties":false},"when":{"type":"object","properties":{"occurrenceId":{"type":"string","description":"The date booked; a listing page opened with `?time=` and this id lands on it."},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"timezone":{"type":"string"},"dayLabel":{"type":"string"},"timeRangeLabel":{"type":"string"},"timezoneLabel":{"type":"string"}},"required":["occurrenceId","startsAt","endsAt","timezone","dayLabel","timeRangeLabel","timezoneLabel"],"additionalProperties":false},"location":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"address":{"type":"string"},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"timezone":{"type":"string"},"contactEmail":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactPhone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","slug","address","lat","lng","timezone","contactEmail","contactPhone"],"additionalProperties":false},"business":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"contactEmail":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","slug","contactEmail"],"additionalProperties":false},"party":{"type":"object","properties":{"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"customerEmailMasked":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["size","customerName","customerEmailMasked"],"additionalProperties":false},"money":{"type":"object","properties":{"currency":{"$ref":"#/components/schemas/Currency"},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"amountPaid":{"$ref":"#/components/schemas/MoneyAmount"},"amountDue":{"$ref":"#/components/schemas/MoneyAmount"},"amountTotalLabel":{"type":"string"},"amountPaidLabel":{"type":"string"},"amountDueLabel":{"type":"string"},"refundExpected":{"type":"boolean"},"refundLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"balanceCollectAtLabel":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["currency","amountTotal","amountPaid","amountDue","amountTotalLabel","amountPaidLabel","amountDueLabel","refundExpected","refundLabel","balanceCollectAtLabel"],"additionalProperties":false},"enrollment":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"seriesName":{"type":"string"},"accountHref":{"type":"string"}},"required":["id","seriesName","accountHref"],"additionalProperties":false},{"type":"null"}]},"subscription":{"description":"A subscription's session (build-plan/280): the subscription it belongs to — the page says Can't make it, never money.","anyOf":[{"type":"object","properties":{"membershipId":{"$ref":"#/components/schemas/Uuid"},"listingName":{"type":"string"}},"required":["membershipId","listingName"],"additionalProperties":false},{"type":"null"}]},"policy":{"type":"object","properties":{"canCancelOnline":{"type":"boolean"},"canRescheduleOnline":{"type":"boolean"},"inCancelWindow":{"type":"boolean","description":"Before the cancel deadline — a cancel now is in-window."},"refundExpected":{"type":"boolean"},"changesCloseAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"changesCloseAtLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"closedReason":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["canCancelOnline","canRescheduleOnline","inCancelWindow","refundExpected","changesCloseAt","changesCloseAtLabel","closedReason"],"additionalProperties":false},"answers":{"type":"array","items":{"type":"object","properties":{"prompt":{"type":"string"},"valueLabel":{"type":"string"}},"required":["prompt","valueLabel"],"additionalProperties":false}},"pieces":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"fulfilled":{"type":"boolean"}},"required":["label","fulfilled"],"additionalProperties":false}},"cartHref":{"anyOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"dateFormat":{"type":"string","enum":["MDY","DMY","YMD"]}},"required":["id","reference","status","listing","when","location","business","party","money","policy","answers","pieces","cartHref","locale","dateFormat"],"additionalProperties":false,"description":"Capability-surface booking view for the manage link (architecture/17). Email is masked; no booked_by or payment identifiers.","example":{"id":"550e8400-e29b-41d4-a716-446655440005","reference":"BK-550E8400","status":"confirmed","listing":{"id":"550e8400-e29b-41d4-a716-446655440004","name":"Vinyasa Flow","slug":"vinyasa-flow","type":"class","capacity":12,"bookingHorizonDays":28,"spotsLeft":"few","confirmationMessage":"Bring a mat.","meetingUrl":null,"meetingInstructions":null},"when":{"occurrenceId":"550e8400-e29b-41d4-a716-446655440013","startsAt":"2026-08-01T18:00:00.000Z","endsAt":"2026-08-01T19:00:00.000Z","timezone":"America/Denver","dayLabel":"Sat, Aug 1, 2026","timeRangeLabel":"12:00 PM – 1:00 PM","timezoneLabel":"America/Denver"},"location":{"name":"Main Hall","slug":"main-hall","address":"9 Link St","lat":null,"lng":null,"timezone":"America/Denver","contactEmail":"hello@example.com","contactPhone":null},"business":{"name":"Sunrise Studio","slug":"sunrise-studio","contactEmail":"hello@example.com"},"party":{"size":1,"customerName":"Alex Rivera","customerEmailMasked":"a•••@example.com"},"money":{"currency":"USD","amountTotal":4500,"amountPaid":4500,"amountDue":0,"amountTotalLabel":"$45.00","amountPaidLabel":"$45.00","amountDueLabel":"$0.00","refundExpected":true,"refundLabel":"$45.00","balanceCollectAtLabel":null},"policy":{"canCancelOnline":true,"canRescheduleOnline":true,"inCancelWindow":true,"refundExpected":true,"changesCloseAt":"2026-07-31T18:00:00.000Z","changesCloseAtLabel":"Fri, Jul 31, 2026, 12:00 PM","closedReason":null},"answers":[],"cartHref":null,"locale":"en-US","dateFormat":"MDY"}},"BookingFeedback":{"type":"object","properties":{"rating":{"$ref":"#/components/schemas/FeedbackRating"},"comment":{"anyOf":[{"type":"string"},{"type":"null"}]},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When the thumb was last given."}},"required":["rating","comment","at"],"additionalProperties":false,"example":{"rating":"up","comment":null,"at":"2026-10-11T17:04:00.000Z"}},"JourneyStep":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"type":"string"},"action":{"type":"string","enum":["confirmation","reminder","check_in","collect_balance","check_out","complete","message","milestone"]},"mode":{"type":"string","enum":["auto","manual"]},"anchor":{"anyOf":[{"type":"string","enum":["session_start","session_end","step"]},{"type":"null"}]},"anchorStepId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"anyOf":[{"type":"object","properties":{"subject":{"type":"string"},"body":{"type":"string"}},"required":["subject","body"],"additionalProperties":false},{"type":"null"}]},"closes":{"type":"boolean"},"pieceStage":{"description":"The piece stage this step marks (build-plan/277): moving pieces to it marks the step, counted in pieces.","anyOf":[{"type":"string","enum":["in_kiln","ready","picked_up"]},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"sentence":{"type":"string"}},"required":["id","businessId","offeringId","position","name","action","mode","anchor","anchorStepId","offsetMinutes","message","closes","createdAt","updatedAt","sentence"],"additionalProperties":false,"description":"A journey step definition with its server-built sentence (architecture/29). `sentence` is Name · when · channel.","example":{"id":"550e8400-e29b-41d4-a716-446655440025","businessId":"550e8400-e29b-41d4-a716-446655440002","offeringId":null,"position":4,"name":"Pickup reminder","action":"message","mode":"auto","anchor":"step","anchorStepId":"550e8400-e29b-41d4-a716-446655440004","offsetMinutes":20160,"message":{"subject":"Your pieces are waiting","body":"Still here for you."},"closes":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","sentence":"Pickup reminder · 14 days after Ready for pickup · email"}},"RemoveJourneyStepResult":{"type":"object","properties":{"pendingBookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["pendingBookings"],"additionalProperties":false,"description":"How many in-flight bookings still have a pending copy of the archived step.","example":{"pendingBookings":2}},"ListingJourney":{"type":"object","properties":{"studio":{"type":"array","items":{"$ref":"#/components/schemas/ListingJourneyStep"}},"own":{"type":"array","items":{"$ref":"#/components/schemas/JourneyStep"}},"pieces":{"description":"The listing's Pieces switch (build-plan/277 D14). On the chapter read.","type":"boolean"},"pickupLine":{"description":"The line under the customer's pieces. On the chapter read.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["studio","own"],"additionalProperties":false,"description":"The listing Journey chapter: studio steps (with off) then this listing's own; the read adds the Pieces switch and its pickup line.","example":{"studio":[{"id":"550e8400-e29b-41d4-a716-446655440025","businessId":"550e8400-e29b-41d4-a716-446655440002","offeringId":null,"position":4,"name":"Thank you","action":"message","mode":"auto","anchor":"step","anchorStepId":"550e8400-e29b-41d4-a716-446655440004","offsetMinutes":20160,"message":{"subject":"Your pieces are waiting","body":"Still here for you."},"closes":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","sentence":"Thank you · 2 hours after the session ends · email","off":false}],"own":[{"id":"550e8400-e29b-41d4-a716-446655440025","businessId":"550e8400-e29b-41d4-a716-446655440002","offeringId":null,"position":4,"name":"Pickup reminder","action":"message","mode":"auto","anchor":"step","anchorStepId":"550e8400-e29b-41d4-a716-446655440004","offsetMinutes":20160,"message":{"subject":"Your pieces are waiting","body":"Still here for you."},"closes":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","sentence":"Pickup reminder · 14 days after Ready for pickup · email"}]}},"ListingJourneyStep":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"offeringId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"type":"string"},"action":{"type":"string","enum":["confirmation","reminder","check_in","collect_balance","check_out","complete","message","milestone"]},"mode":{"type":"string","enum":["auto","manual"]},"anchor":{"anyOf":[{"type":"string","enum":["session_start","session_end","step"]},{"type":"null"}]},"anchorStepId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"anyOf":[{"type":"object","properties":{"subject":{"type":"string"},"body":{"type":"string"}},"required":["subject","body"],"additionalProperties":false},{"type":"null"}]},"closes":{"type":"boolean"},"pieceStage":{"description":"The piece stage this step marks (build-plan/277): moving pieces to it marks the step, counted in pieces.","anyOf":[{"type":"string","enum":["in_kiln","ready","picked_up"]},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"sentence":{"type":"string"},"off":{"type":"boolean"},"timing":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","enum":["auto","manual"]},"anchor":{"anyOf":[{"type":"string","enum":["session_start","session_end","step"]},{"type":"null"}]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["mode","anchor","offsetMinutes"],"additionalProperties":false},{"type":"null"}],"description":"The listing's own timing for Check in or Check out; null = the studio's."},"timingSentence":{"description":"The step's sentence with the listing's timing, when retimed.","type":"string"}},"required":["id","businessId","offeringId","position","name","action","mode","anchor","anchorStepId","offsetMinutes","message","closes","createdAt","updatedAt","sentence","off","timing"],"additionalProperties":false,"description":"A studio step as a listing sees it, with its off and timing overrides.","example":{"id":"550e8400-e29b-41d4-a716-446655440025","businessId":"550e8400-e29b-41d4-a716-446655440002","offeringId":null,"position":4,"name":"Pickup reminder","action":"message","mode":"auto","anchor":"step","anchorStepId":"550e8400-e29b-41d4-a716-446655440004","offsetMinutes":20160,"message":{"subject":"Your pieces are waiting","body":"Still here for you."},"closes":false,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","sentence":"Pickup reminder · 14 days after Ready for pickup · email","off":false,"timing":null}},"ArriveAndLeave":{"type":"object","properties":{"mode":{"type":"string","enum":["automatic","manual_checkout","manual"],"description":"automatic: checked in at the start and out at the end by themselves. manual_checkout: checked in by itself, out by the desk — the place stays taken until checked out. manual: the desk checks them in and out, and the check-in sheet asks before checking in over capacity."},"checkIn":{"anyOf":[{"type":"object","properties":{"anchor":{"type":"string","enum":["session_start","session_end"]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minutes after the anchor, 0 to a day."}},"required":["anchor","offsetMinutes"],"additionalProperties":false},{"type":"null"}],"description":"Null: the desk checks them in."},"checkOut":{"anyOf":[{"type":"object","properties":{"anchor":{"type":"string","enum":["session_start","session_end"]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minutes after the anchor, 0 to a day."}},"required":["anchor","offsetMinutes"],"additionalProperties":false},{"type":"null"}],"description":"Null: the desk checks them out."},"complete":{"type":"string","enum":["auto","manual"]}},"required":["mode","checkIn","checkOut","complete"],"additionalProperties":false,"description":"Check in, Check out and Complete said as one mode — the business's (build-plan/292).","example":{"mode":"automatic","checkIn":{"anchor":"session_start","offsetMinutes":0},"checkOut":{"anchor":"session_end","offsetMinutes":0},"complete":"auto"}},"ListingArriveAndLeave":{"type":"object","properties":{"mode":{"type":"string","enum":["automatic","manual_checkout","manual"],"description":"automatic: checked in at the start and out at the end by themselves. manual_checkout: checked in by itself, out by the desk — the place stays taken until checked out. manual: the desk checks them in and out, and the check-in sheet asks before checking in over capacity."},"checkIn":{"anyOf":[{"type":"object","properties":{"anchor":{"type":"string","enum":["session_start","session_end"]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minutes after the anchor, 0 to a day."}},"required":["anchor","offsetMinutes"],"additionalProperties":false},{"type":"null"}]},"checkOut":{"anyOf":[{"type":"object","properties":{"anchor":{"type":"string","enum":["session_start","session_end"]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minutes after the anchor, 0 to a day."}},"required":["anchor","offsetMinutes"],"additionalProperties":false},{"type":"null"}]},"complete":{"type":"string","enum":["auto","manual"]},"own":{"type":"boolean","description":"The listing runs its own timing on at least one of the three steps."},"business":{"$ref":"#/components/schemas/ArriveAndLeave"}},"required":["mode","checkIn","checkOut","complete","own","business"],"additionalProperties":false,"description":"A listing's Arrive and leave as it runs, with the business's beside it (build-plan/292).","example":{"mode":"manual_checkout","checkIn":{"anchor":"session_start","offsetMinutes":0},"checkOut":null,"complete":"auto","own":true,"business":{"mode":"automatic","checkIn":{"anchor":"session_start","offsetMinutes":0},"checkOut":{"anchor":"session_end","offsetMinutes":0},"complete":"auto"}}},"ListingPieces":{"type":"object","properties":{"pieces":{"type":"boolean"},"pickupLine":{"anyOf":[{"type":"string"},{"type":"null"}]},"journey":{"$ref":"#/components/schemas/ListingJourney"}},"required":["pieces","pickupLine","journey"],"additionalProperties":false,"description":"The listing's Pieces switch, its pickup line and its journey chapter after the change."},"BookingJourney":{"type":"object","properties":{"steps":{"type":"array","items":{"$ref":"#/components/schemas/BookingStep"}},"next":{"anyOf":[{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"dueAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"sentence":{"type":"string"}},"required":["id","name","dueAt","sentence"],"additionalProperties":false},{"type":"null"}]}},"required":["steps","next"],"additionalProperties":false,"description":"The booking's checklist and the next pending step. Collect balance is omitted when the snapshot has no later amount.","example":{"steps":[{"id":"550e8400-e29b-41d4-a716-446655440026","bookingId":"550e8400-e29b-41d4-a716-446655440005","stepId":"550e8400-e29b-41d4-a716-446655440025","position":8,"name":"Ready for pickup","action":"message","mode":"manual","anchor":null,"anchorStepId":null,"offsetMinutes":0,"closes":false,"hasMessage":true,"status":"pending","dueAt":null,"doneAt":null,"actorType":null,"actorId":null,"note":null,"taskId":null,"result":null,"doneCount":6,"partySize":8,"sendCount":1,"sentence":"Ready for pickup · by hand · email"}],"next":{"id":"550e8400-e29b-41d4-a716-446655440026","name":"Ready for pickup","dueAt":null,"sentence":"Ready for pickup · by hand · email"}}},"BookingStep":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"bookingId":{"$ref":"#/components/schemas/Uuid"},"stepId":{"$ref":"#/components/schemas/Uuid"},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"name":{"type":"string"},"action":{"type":"string","enum":["confirmation","reminder","check_in","collect_balance","check_out","complete","message","milestone"]},"mode":{"type":"string","enum":["auto","manual"]},"anchor":{"anyOf":[{"type":"string","enum":["session_start","session_end","step"]},{"type":"null"}]},"anchorStepId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"offsetMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closes":{"type":"boolean"},"hasMessage":{"type":"boolean"},"pieceStage":{"description":"Set on a step that marks a piece stage (build-plan/277): `doneCount` and `partySize` are then pieces.","anyOf":[{"type":"string","enum":["in_kiln","ready","picked_up"]},{"type":"null"}]},"status":{"type":"string","enum":["pending","done","skipped","canceled"]},"dueAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"doneAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"actorType":{"anyOf":[{"type":"string","enum":["customer","user","system"]},{"type":"null"}]},"actorId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"taskId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"result":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"doneCount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sendCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sentence":{"type":"string"}},"required":["id","bookingId","stepId","position","name","action","mode","anchor","anchorStepId","offsetMinutes","closes","hasMessage","status","dueAt","doneAt","actorType","actorId","note","taskId","result","doneCount","partySize","sendCount","sentence"],"additionalProperties":false,"description":"One booking's copy of a step. `doneCount` is null when the mark is for the whole booking; read with `partySize` as \"6 of 8\".","example":{"id":"550e8400-e29b-41d4-a716-446655440026","bookingId":"550e8400-e29b-41d4-a716-446655440005","stepId":"550e8400-e29b-41d4-a716-446655440025","position":8,"name":"Ready for pickup","action":"message","mode":"manual","anchor":null,"anchorStepId":null,"offsetMinutes":0,"closes":false,"hasMessage":true,"status":"pending","dueAt":null,"doneAt":null,"actorType":null,"actorId":null,"note":null,"taskId":null,"result":null,"doneCount":6,"partySize":8,"sendCount":1,"sentence":"Ready for pickup · by hand · email"}},"JourneyStepActionPreview":{"type":"object","properties":{"preview":{"type":"boolean","const":true},"verb":{"type":"string","enum":["mark","skip","run"]},"sentence":{"type":"string"},"bookingStepId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"action":{"type":"string","enum":["confirmation","reminder","check_in","collect_balance","check_out","complete","message","milestone"]},"count":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"email":{"anyOf":[{"type":"object","properties":{"to":{"type":"string"},"subject":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["to","subject"],"additionalProperties":false},{"type":"null"}]},"closes":{"type":"boolean"},"cancels":{"type":"array","items":{"type":"string"}}},"required":["preview","verb","sentence","bookingStepId","name","action","count","partySize","email","closes","cancels"],"additionalProperties":false,"description":"Unacknowledged Mark / Skip / Run now: what will be marked, who is emailed, what a closing step cancels.","example":{"preview":true,"verb":"mark","sentence":"Mark Ready for pickup · 6 of 8 · emails Jane","bookingStepId":"550e8400-e29b-41d4-a716-446655440026","name":"Ready for pickup","action":"message","count":6,"partySize":8,"email":{"to":"Jane","subject":"Your pieces are ready"},"closes":false,"cancels":[]}},"JourneyStepActionResult":{"type":"object","properties":{"preview":{"type":"boolean","const":false},"sentence":{"type":"string"},"step":{"$ref":"#/components/schemas/BookingStep"}},"required":["preview","sentence","step"],"additionalProperties":false,"description":"The step after an acknowledged Mark / Skip / Run now, with the preview sentence the console showed.","example":{"preview":false,"sentence":"Mark Ready for pickup · 6 of 8 · emails Jane","step":{"id":"550e8400-e29b-41d4-a716-446655440026","bookingId":"550e8400-e29b-41d4-a716-446655440005","stepId":"550e8400-e29b-41d4-a716-446655440025","position":8,"name":"Ready for pickup","action":"message","mode":"manual","anchor":null,"anchorStepId":null,"offsetMinutes":0,"closes":false,"hasMessage":true,"status":"done","dueAt":null,"doneAt":null,"actorType":null,"actorId":null,"note":null,"taskId":null,"result":null,"doneCount":null,"partySize":8,"sendCount":1,"sentence":"Ready for pickup · by hand · email"}}},"JourneyOccurrenceMarkPreview":{"type":"object","properties":{"preview":{"type":"boolean","const":true},"verb":{"type":"string","const":"mark"},"sentence":{"type":"string"},"pending":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"alreadyThere":{"type":"array","items":{"type":"string"}}},"required":["preview","verb","sentence","pending","alreadyThere"],"additionalProperties":false,"example":{"preview":true,"verb":"mark","sentence":"Mark In the kiln · 2 bookings","pending":2,"alreadyThere":[]}},"JourneyOccurrenceMarkResult":{"type":"object","properties":{"preview":{"type":"boolean","const":false},"sentence":{"type":"string"},"marked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"alreadyThere":{"type":"array","items":{"type":"string"}}},"required":["preview","sentence","marked","alreadyThere"],"additionalProperties":false,"description":"`alreadyThere` is the first names of bookings already past the step.","example":{"preview":false,"sentence":"Mark In the kiln · 2 bookings","marked":2,"alreadyThere":[]}},"BookingPieces":{"type":"object","properties":{"pieces":{"type":"array","items":{"$ref":"#/components/schemas/Piece"}},"slots":{"type":"array","items":{"type":"object","properties":{"orderLineId":{"$ref":"#/components/schemas/Uuid"},"label":{"type":"string"},"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pieces still to photograph for this add-on."}},"required":["orderLineId","label","remaining"],"additionalProperties":false},"description":"The booking's required add-ons not yet matched by a piece — the tiles waiting for a photo."},"stepNames":{"$ref":"#/components/schemas/PieceStepNames"},"pickupLine":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The listing's line under the customer's pieces."},"shelves":{"type":"array","items":{"type":"string"},"description":"The location's shelf IDs, in its order; empty when it keeps none."}},"required":["pieces","slots","stepNames","pickupLine","shelves"],"additionalProperties":false,"example":{"pieces":[{"id":"019a0000-0000-7000-8000-0000000002a1","bookingId":"019a0000-0000-7000-8000-0000000002b1","label":"Maya's giraffe","labelSource":"desk","stage":"ready","stageAt":"2026-10-12T16:20:00.000Z","shelf":"B1","addedBy":"desk","orderLineId":null,"photos":[{"id":"019a0000-0000-7000-8000-0000000002c1","url":"https://private-media.example/pieces/b/p/photo.jpg?X-Amz-Expires=3600","width":1600,"height":1200}]}],"slots":[{"orderLineId":"019a0000-0000-7000-8000-0000000002d1","label":"Mug","remaining":1}],"stepNames":{"inKiln":"In the kiln","ready":"Ready for pickup","pickedUp":"Picked up"},"pickupLine":"Usually ready in about a week. We keep pieces 30 days after they're ready.","shelves":["A1","A2","B1"]}},"Piece":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"bookingId":{"$ref":"#/components/schemas/Uuid"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What it is — *Giraffe*, *Maya's giraffe*. At most 60 characters."},"labelSource":{"type":"string","enum":["desk","customer","product","suggested"],"description":"`desk` typed it, `customer` added it, `product` is the add-on it fills, `suggested` came from the photo."},"stage":{"$ref":"#/components/schemas/PieceStage"},"stageAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When it reached its stage — the shelf's age."},"shelf":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Where it sits, for the desk only: one of the location's shelves, or free text where it keeps none. Never set in the kiln."},"addedBy":{"type":"string","enum":["desk","customer"]},"orderLineId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"The required add-on line this piece is, if any."},"photos":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"url":{"type":"string","format":"uri","description":"A signed read of the JPEG, good for an hour. Never stored or shared."},"width":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","url","width","height"],"additionalProperties":false},"description":"Up to 5, in order; the first is the cover. Empty for a piece without a picture. A piece photographed before the cap was 5 keeps the ones it has."}},"required":["id","bookingId","label","labelSource","stage","stageAt","shelf","addedBy","orderLineId","photos"],"additionalProperties":false,"description":"One thing a customer made, on their booking.","example":{"id":"019a0000-0000-7000-8000-0000000002a1","bookingId":"019a0000-0000-7000-8000-0000000002b1","label":"Maya's giraffe","labelSource":"desk","stage":"ready","stageAt":"2026-10-12T16:20:00.000Z","shelf":"B1","addedBy":"desk","orderLineId":null,"photos":[{"id":"019a0000-0000-7000-8000-0000000002c1","url":"https://private-media.example/pieces/b/p/photo.jpg?X-Amz-Expires=3600","width":1600,"height":1200}]}},"PieceStepNames":{"type":"object","properties":{"inKiln":{"type":"string"},"ready":{"type":"string"},"pickedUp":{"type":"string"}},"required":["inKiln","ready","pickedUp"],"additionalProperties":false,"description":"The names of the listing's steps tagged with each stage, or *In the kiln* · *Ready for pickup* · *Picked up*."},"OccurrencePieces":{"type":"object","properties":{"offeringName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The session's listing. Null on a date nobody has booked yet (it has no row) or that is not this business's."},"localStart":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The session's start on the location's clock, `yyyy-MM-ddTHH:mm`; null as above."},"localEnd":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The session's end on the location's clock, `yyyy-MM-ddTHH:mm`; null as above."},"bookings":{"type":"array","items":{"type":"object","properties":{"bookingId":{"$ref":"#/components/schemas/Uuid"},"customerName":{"type":"string","description":"Who the booking is — *Guest* when it has no customer."},"partySize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Its spots: the camera's dots."},"reference":{"type":"string","description":"The booking reference, `BK-…`."},"slots":{"type":"array","items":{"type":"object","properties":{"orderLineId":{"$ref":"#/components/schemas/Uuid"},"label":{"type":"string"},"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pieces still to photograph for this add-on."}},"required":["orderLineId","label","remaining"],"additionalProperties":false},"description":"Its required add-ons not yet matched by a piece, as the booking's own read gives them."},"pieces":{"type":"array","items":{"$ref":"#/components/schemas/Piece"},"description":"The booking's live pieces in their order; empty for a party with none yet."}},"required":["bookingId","customerName","partySize","reference","slots","pieces"],"additionalProperties":false},"description":"Every booking on the date that can hold pieces (confirmed, checked in or out, completed), oldest first, once the date tracks them. Empty when the listing has Pieces off and no booking on the date has a piece."},"stepNames":{"$ref":"#/components/schemas/PieceStepNames"}},"required":["offeringName","localStart","localEnd","bookings","stepNames"],"additionalProperties":false,"example":{"offeringName":"Paint your own","localStart":"2026-10-17T14:00","localEnd":"2026-10-17T16:00","bookings":[{"bookingId":"019a0000-0000-7000-8000-0000000002b1","customerName":"Jane Rivera","partySize":2,"reference":"BK-7Q2M4KX9","slots":[{"orderLineId":"019a0000-0000-7000-8000-0000000002d1","label":"Mug","remaining":1}],"pieces":[{"id":"019a0000-0000-7000-8000-0000000002a1","bookingId":"019a0000-0000-7000-8000-0000000002b1","label":"Maya's giraffe","labelSource":"desk","stage":"ready","stageAt":"2026-10-12T16:20:00.000Z","shelf":"B1","addedBy":"desk","orderLineId":null,"photos":[{"id":"019a0000-0000-7000-8000-0000000002c1","url":"https://private-media.example/pieces/b/p/photo.jpg?X-Amz-Expires=3600","width":1600,"height":1200}]}]},{"bookingId":"019a0000-0000-7000-8000-0000000002b2","customerName":"Sam Okafor","partySize":1,"reference":"BK-3HD8W2PQ","slots":[],"pieces":[]}],"stepNames":{"inKiln":"In the kiln","ready":"Ready for pickup","pickedUp":"Picked up"}}},"PieceReminder":{"type":"object","properties":{"bookingStepId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string","description":"The step that ran — *Pickup reminder*, then *Last call*."},"status":{"type":"string","description":"The step after the run: `done` once it sent, `skipped` when it found nobody to reach."}},"required":["bookingStepId","name","status"],"additionalProperties":false,"example":{"bookingStepId":"019a0000-0000-7000-8000-0000000002a1","name":"Pickup reminder","status":"done"}},"PieceShelf":{"type":"object","properties":{"groups":{"type":"array","items":{"type":"object","properties":{"booking":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"reference":{"type":"string"},"customerName":{"type":"string"},"listingName":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","reference","customerName","listingName","startsAt"],"additionalProperties":false},"pieces":{"type":"array","items":{"$ref":"#/components/schemas/Piece"}},"stageDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Whole days the group's oldest piece has been at this stage."}},"required":["booking","pieces","stageDays"],"additionalProperties":false}},"counts":{"type":"object","properties":{"made":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"inKiln":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"ready":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"pickedUp":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["made","inKiln","ready","pickedUp"],"additionalProperties":false,"description":"Every pill's count, under the same shelf and search."},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Picked up only: pass as `cursor` for the next page."},"shelves":{"description":"The location's shelf IDs, in its order; empty when it keeps none. Not on an instructor's empty shelf.","type":"array","items":{"type":"string"}},"stepNames":{"description":"The names the location's pieces listings give the stages when they agree, else the defaults — the pills' words.","$ref":"#/components/schemas/PieceStepNames"},"tracksPieces":{"description":"A listing here has Pieces on, or a live piece is here: Pickups shows Made · In the kiln · Ready · Picked up.","type":"boolean"}},"required":["groups","counts","nextCursor"],"additionalProperties":false,"example":{"groups":[{"booking":{"id":"019a0000-0000-7000-8000-0000000002b1","reference":"BK-7Q2M4KX9","customerName":"Jane Rivera","listingName":"Paint your own","startsAt":"2026-10-10T20:00:00.000Z"},"pieces":[{"id":"019a0000-0000-7000-8000-0000000002a1","bookingId":"019a0000-0000-7000-8000-0000000002b1","label":"Maya's giraffe","labelSource":"desk","stage":"ready","stageAt":"2026-10-12T16:20:00.000Z","shelf":"B1","addedBy":"desk","orderLineId":null,"photos":[{"id":"019a0000-0000-7000-8000-0000000002c1","url":"https://private-media.example/pieces/b/p/photo.jpg?X-Amz-Expires=3600","width":1600,"height":1200}]}],"stageDays":0}],"counts":{"made":14,"inKiln":22,"ready":4,"pickedUp":310},"nextCursor":null,"shelves":["A1","A2","B1"],"stepNames":{"inKiln":"In the kiln","ready":"Ready for pickup","pickedUp":"Picked up"},"tracksPieces":true}},"PieceMovePreview":{"type":"object","properties":{"sentence":{"type":"string","description":"The verb with its count — *In the kiln · 4 pieces*."},"pieces":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pieces that would move; those already at the stage are left."},"bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"notify":{"anyOf":[{"type":"object","properties":{"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"channel":{"type":"string"}},"required":["people","channel"],"additionalProperties":false},{"type":"null"}],"description":"Who the stage's step would tell — bookings whose pending message step the move marks, with a customer it can reach — and how: `sms`, `email` or `mixed`. Null when nobody."}},"required":["sentence","pieces","bookings","notify"],"additionalProperties":false},"PieceMoveResult":{"type":"object","properties":{"moved":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"undoUntil":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"Until when moving back cancels the message the move scheduled (the ten-minute grace, build-plan/277 D8). Null when no message was scheduled."}},"required":["moved","undoUntil"],"additionalProperties":false},"PieceName":{"type":"object","properties":{"pieceId":{"$ref":"#/components/schemas/Uuid"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The piece's name now: the suggestion, the name it already had, or null when the photo named nothing."},"labelSource":{"type":"string","enum":["desk","customer","product","suggested"]}},"required":["pieceId","label","labelSource"],"additionalProperties":false,"example":{"pieceId":"019a0000-0000-7000-8000-0000000002a1","label":"Giraffe","labelSource":"suggested"}},"PlaceAutocompleteResponse":{"type":"object","properties":{"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/PlaceSuggestion"}}},"required":["suggestions"],"additionalProperties":false},"PlaceSuggestion":{"type":"object","properties":{"placeId":{"type":"string"},"primaryText":{"type":"string"},"secondaryText":{"type":"string"}},"required":["placeId","primaryText","secondaryText"],"additionalProperties":false},"PlaceDetailsResponse":{"type":"object","properties":{"formattedAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"lat":{"anyOf":[{"type":"number"},{"type":"null"}]},"lng":{"anyOf":[{"type":"number"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"region":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"line1":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Street number and street (`350 5th Ave`)."},"line2":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Apartment or suite, when the place has one."}},"required":["formattedAddress","lat","lng","country","region","city","postalCode","line1","line2"],"additionalProperties":false},"ProductPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["items","nextCursor"],"additionalProperties":false,"example":{"items":[{"id":"550e8400-e29b-41d4-a716-446655440027","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Bisque piece","description":"Paint it in class; we glaze and fire it.","status":"published","shopListed":true,"taxable":true,"revenueCategoryId":null,"trackInventory":true,"displayOrder":1,"slug":null,"soldVia":"shop","offeredWith":[],"variants":[{"id":"550e8400-e29b-41d4-a716-446655440028","productId":"550e8400-e29b-41d4-a716-446655440027","name":"Mug","sku":"BQ-MUG","priceAmount":1200,"priceCurrency":"USD","sortIndex":0,"onHand":12,"available":12,"stock":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","onHand":12,"available":12}]},{"id":"550e8400-e29b-41d4-a716-446655440029","productId":"550e8400-e29b-41d4-a716-446655440027","name":"Bowl","sku":"BQ-BOWL","priceAmount":1800,"priceCurrency":"USD","sortIndex":1,"onHand":3,"available":3,"stock":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","onHand":3,"available":3}]}],"priceFrom":1200,"onHand":15,"lowStock":{"variantId":"550e8400-e29b-41d4-a716-446655440029","name":"Bowl","onHand":3},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}],"nextCursor":null}},"Product":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"Sold at: the one location that sells it — where it was made — or null for every location, which only an owner sets. The shop, the product page, listing add-ons and holds all follow it."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","published","hidden","archived"],"description":"Draft · For sale (`published`) · Hidden · Archived."},"shopListed":{"type":"boolean","description":"Appears in the shop with its own page. Independent of being offered with a listing."},"taxable":{"type":"boolean"},"revenueCategoryId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"What this is in the studio's books and which taxes it carries (architecture/31). With one, `taxable` is inert. Null = none."},"trackInventory":{"type":"boolean","description":"False never runs out and writes no stock rows."},"displayOrder":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"slug":{"anyOf":[{"type":"string"},{"type":"null"}]},"soldVia":{"type":"string","enum":["shop","add_on","both","none"],"description":"Where it sells, derived from `shopListed` and the listings offering it."},"offeredWith":{"type":"array","items":{"type":"object","properties":{"offeringId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["offeringId","name"],"additionalProperties":false},"description":"The listings offering this product as an add-on."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/ProductVariant"},"description":"Live options in `sortIndex` order."},"priceFrom":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}],"description":"The cheapest live price — \"from $12\"."},"onHand":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Across options and locations; null when not tracked."},"lowStock":{"anyOf":[{"type":"object","properties":{"variantId":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"onHand":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["variantId","name","onHand"],"additionalProperties":false},{"type":"null"}],"description":"The lowest option when it is at 5 or under."},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","locationId","name","description","status","shopListed","taxable","revenueCategoryId","trackInventory","displayOrder","slug","soldVia","offeredWith","variants","priceFrom","onHand","lowStock","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"description":"A thing the studio sells, with one or more options (architecture/26).","example":{"id":"550e8400-e29b-41d4-a716-446655440027","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Bisque piece","description":"Paint it in class; we glaze and fire it.","status":"published","shopListed":true,"taxable":true,"revenueCategoryId":null,"trackInventory":true,"displayOrder":1,"slug":null,"soldVia":"shop","offeredWith":[],"variants":[{"id":"550e8400-e29b-41d4-a716-446655440028","productId":"550e8400-e29b-41d4-a716-446655440027","name":"Mug","sku":"BQ-MUG","priceAmount":1200,"priceCurrency":"USD","sortIndex":0,"onHand":12,"available":12,"stock":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","onHand":12,"available":12}]},{"id":"550e8400-e29b-41d4-a716-446655440029","productId":"550e8400-e29b-41d4-a716-446655440027","name":"Bowl","sku":"BQ-BOWL","priceAmount":1800,"priceCurrency":"USD","sortIndex":1,"onHand":3,"available":3,"stock":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","onHand":3,"available":3}]}],"priceFrom":1200,"onHand":15,"lowStock":{"variantId":"550e8400-e29b-41d4-a716-446655440029","name":"Bowl","onHand":3},"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"ProductVariant":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"productId":{"$ref":"#/components/schemas/Uuid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Null on a single-option product."},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"priceAmount":{"anyOf":[{"$ref":"#/components/schemas/MoneyAmount"},{"type":"null"}],"description":"Null only while the product is not for sale."},"priceCurrency":{"$ref":"#/components/schemas/Currency"},"sortIndex":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"onHand":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Across locations; null when the product does not track stock."},"available":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Across locations; null when the product does not track stock."},"stock":{"type":"array","items":{"type":"object","properties":{"locationId":{"$ref":"#/components/schemas/Uuid"},"onHand":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The stock ledger's sum at this location."},"available":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"What can be sold now: on hand less live holds. Equal to `onHand` until purchase lines hold stock."}},"required":["locationId","onHand","available"],"additionalProperties":false},"description":"One entry per location with any stock row; empty when the product does not track stock."}},"required":["id","productId","name","sku","priceAmount","priceCurrency","sortIndex","onHand","available","stock"],"additionalProperties":false,"description":"One option of a product, with its own price, SKU and stock. The console calls it an option.","example":{"id":"550e8400-e29b-41d4-a716-446655440028","productId":"550e8400-e29b-41d4-a716-446655440027","name":"Mug","sku":"BQ-MUG","priceAmount":1200,"priceCurrency":"USD","sortIndex":0,"onHand":12,"available":12,"stock":[{"locationId":"550e8400-e29b-41d4-a716-446655440003","onHand":12,"available":12}]}},"StockMovementPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StockMovement"}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["items","nextCursor"],"additionalProperties":false,"example":{"items":[{"id":"550e8400-e29b-41d4-a716-446655440030","businessId":"550e8400-e29b-41d4-a716-446655440002","variantId":"550e8400-e29b-41d4-a716-446655440028","locationId":"550e8400-e29b-41d4-a716-446655440003","delta":-3,"reason":"counted","orderLineId":null,"actorType":"user","actorId":"550e8400-e29b-41d4-a716-446655440001","memo":"Friday count","occurredAt":"2026-07-24T12:00:00.000Z","createdAt":"2026-07-24T12:00:00.000Z"}],"nextCursor":null}},"StockMovement":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"variantId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"delta":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Signed units: + onto the shelf, − off it."},"reason":{"type":"string","enum":["received","sold","returned","adjusted","counted"]},"orderLineId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"Set on `sold` and `returned` rows only."},"actorType":{"type":"string","enum":["user","system"]},"actorId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"memo":{"anyOf":[{"type":"string"},{"type":"null"}]},"occurredAt":{"$ref":"#/components/schemas/Timestamp"},"createdAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","variantId","locationId","delta","reason","orderLineId","actorType","actorId","memo","occurredAt","createdAt"],"additionalProperties":false,"description":"One signed row of the append-only stock ledger. On hand is the sum of the rows.","example":{"id":"550e8400-e29b-41d4-a716-446655440030","businessId":"550e8400-e29b-41d4-a716-446655440002","variantId":"550e8400-e29b-41d4-a716-446655440028","locationId":"550e8400-e29b-41d4-a716-446655440003","delta":-3,"reason":"counted","orderLineId":null,"actorType":"user","actorId":"550e8400-e29b-41d4-a716-446655440001","memo":"Friday count","occurredAt":"2026-07-24T12:00:00.000Z","createdAt":"2026-07-24T12:00:00.000Z"}},"StockResult":{"type":"object","properties":{"movement":{"$ref":"#/components/schemas/StockMovement"},"onHand":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"On hand at the location after the row."}},"required":["movement","onHand"],"additionalProperties":false,"example":{"movement":{"id":"550e8400-e29b-41d4-a716-446655440030","businessId":"550e8400-e29b-41d4-a716-446655440002","variantId":"550e8400-e29b-41d4-a716-446655440028","locationId":"550e8400-e29b-41d4-a716-446655440003","delta":-3,"reason":"counted","orderLineId":null,"actorType":"user","actorId":"550e8400-e29b-41d4-a716-446655440001","memo":"Friday count","occurredAt":"2026-07-24T12:00:00.000Z","createdAt":"2026-07-24T12:00:00.000Z"},"onHand":5}},"OrderLine":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"description":"Where stock is taken from and the line is collected.","$ref":"#/components/schemas/Uuid"},"variantId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"bookingId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}],"description":"The booking this line is sold with; null for a line bought on its own."},"cartId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"quantity":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"amountTotal":{"$ref":"#/components/schemas/MoneyAmount"},"currency":{"$ref":"#/components/schemas/Currency"},"status":{"type":"string","enum":["held","confirmed","fulfilled","canceled"]},"holdExpiresAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"fulfilledAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"fulfilledBy":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"fulfillmentKind":{"type":"string","enum":["pickup"]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["id","businessId","locationId","variantId","customerId","bookingId","cartId","quantity","amountTotal","currency","status","holdExpiresAt","fulfilledAt","fulfilledBy","fulfillmentKind","createdAt","updatedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440090","businessId":"550e8400-e29b-41d4-a716-446655440001","locationId":"550e8400-e29b-41d4-a716-446655440002","variantId":"550e8400-e29b-41d4-a716-446655440091","customerId":"550e8400-e29b-41d4-a716-446655440004","bookingId":null,"cartId":"550e8400-e29b-41d4-a716-446655440092","quantity":1,"amountTotal":1200,"currency":"USD","status":"fulfilled","holdExpiresAt":null,"fulfilledAt":"2026-09-14T18:00:00.000Z","fulfilledBy":"550e8400-e29b-41d4-a716-446655440005","fulfillmentKind":"pickup","createdAt":"2026-09-14T17:00:00.000Z","updatedAt":"2026-09-14T18:00:00.000Z"}},"PickupLine":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"customerId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"type":"string"},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amountTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units, tax and fee included."},"currency":{"type":"string"},"paidAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"fulfilledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id","locationId","customerId","customerName","productName","variantName","quantity","amountTotal","currency","paidAt","fulfilledAt"],"additionalProperties":false,"description":"A paid product line bought on its own, waiting to be collected or already handed over.","example":{"id":"019a0000-0000-7000-8000-0000000000aa","locationId":"019a0000-0000-7000-8000-0000000000bb","customerId":"019a0000-0000-7000-8000-0000000000cc","customerName":"Jane Rivera","productName":"Glaze jar","variantName":"Celadon","quantity":2,"amountTotal":1776,"currency":"USD","paidAt":"2026-09-17T15:04:05.000Z","fulfilledAt":null}},"Schedule":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"anyOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"name":{"type":"string"},"timezone":{"type":"string"},"rrule":{"type":"string"},"startDate":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"until":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"archivedAt":{"anyOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]}},"required":["id","businessId","locationId","name","timezone","rrule","startDate","until","durationMinutes","createdAt","updatedAt","archivedAt"],"additionalProperties":false,"example":{"id":"550e8400-e29b-41d4-a716-446655440014","businessId":"550e8400-e29b-41d4-a716-446655440002","locationId":"550e8400-e29b-41d4-a716-446655440003","name":"Tuesday evenings","timezone":"America/Denver","rrule":"FREQ=WEEKLY;BYDAY=TU;BYHOUR=18;BYMINUTE=0","startDate":"2026-01-06","until":null,"durationMinutes":90,"createdAt":"2026-07-24T12:00:00.000Z","updatedAt":"2026-07-24T12:00:00.000Z","archivedAt":null}},"ScheduleHealthReport":{"type":"object","properties":{"scheduleId":{"$ref":"#/components/schemas/Uuid"},"healthy":{"type":"boolean"},"issues":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"invalid_timezone | zero_duration | invalid_rrule | no_occurrences"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["scheduleId","healthy","issues"],"additionalProperties":false,"example":{"scheduleId":"550e8400-e29b-41d4-a716-446655440014","healthy":false,"issues":[{"code":"no_occurrences","message":"Schedule does not project any dates in a forward probe window"}]}},"ScheduleOccurrencesResult":{"type":"object","properties":{"scheduleId":{"$ref":"#/components/schemas/Uuid"},"from":{"type":"string"},"to":{"type":"string"},"occurrences":{"type":"array","items":{"$ref":"#/components/schemas/ProjectedOccurrence"}}},"required":["scheduleId","from","to","occurrences"],"additionalProperties":false,"example":{"scheduleId":"550e8400-e29b-41d4-a716-446655440014","from":"2026-01-01T00:00:00.000Z","to":"2026-04-01T00:00:00.000Z","occurrences":[{"occurrenceId":"sched:550e8400-e29b-41d4-a716-446655440014:2026-01-07T01:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-01-07T01:00:00.000Z","endsAt":"2026-01-07T02:30:00.000Z","localStart":"2026-01-06T18:00:00.000-07:00","localEnd":"2026-01-06T19:30:00.000-07:00","timezone":"America/Denver"}]}},"ProjectedOccurrence":{"type":"object","properties":{"occurrenceId":{"type":"string"},"scheduleId":{"$ref":"#/components/schemas/Uuid"},"startsAt":{"$ref":"#/components/schemas/Timestamp"},"endsAt":{"$ref":"#/components/schemas/Timestamp"},"localStart":{"type":"string"},"localEnd":{"type":"string"},"timezone":{"type":"string"}},"required":["occurrenceId","scheduleId","startsAt","endsAt","localStart","localEnd","timezone"],"additionalProperties":false,"example":{"occurrenceId":"sched:550e8400-e29b-41d4-a716-446655440014:2026-01-07T01:00:00.000Z","scheduleId":"550e8400-e29b-41d4-a716-446655440014","startsAt":"2026-01-07T01:00:00.000Z","endsAt":"2026-01-07T02:30:00.000Z","localStart":"2026-01-06T18:00:00.000-07:00","localEnd":"2026-01-06T19:30:00.000-07:00","timezone":"America/Denver"}},"SocialPostDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["occurrence","listing","series","week","plan"]},"title":{"type":"string"},"line":{"type":"string"},"createdAt":{"type":"string"},"createdVia":{"type":"string","enum":["console","ask","mcp"]},"createdBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"canceledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"clicks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidLabel":{"type":"string"},"targets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"network":{"type":"string","enum":["instagram","facebook"]},"format":{"type":"string","enum":["post","story","reel"]},"runAt":{"type":"string"},"status":{"type":"string","enum":["pending","published","failed","canceled"]},"permalink":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"publishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","network","format","runAt","status","permalink","error","publishedAt"],"additionalProperties":false}},"subject":{"type":"object","properties":{"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"occurrenceId":{"type":"string"},"offeringId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"seriesId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"planId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"weekOf":{"type":"string"}},"required":["locationId"],"additionalProperties":false},"locationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"caption":{"type":"string"},"draftCaption":{"anyOf":[{"type":"string"},{"type":"null"}]},"captionEdited":{"type":"boolean"},"photos":{"type":"array","items":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"url":{"anyOf":[{"type":"string"},{"type":"null"}]},"alt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["assetId","url","alt"],"additionalProperties":false}},"formats":{"type":"object","properties":{"instagram":{"type":"array","items":{"type":"string","enum":["post","story"]}},"facebook":{"type":"array","items":{"type":"string","enum":["post","story"]}}},"required":["instagram","facebook"],"additionalProperties":false},"collaborators":{"type":"array","items":{"type":"string"}},"at":{"anyOf":[{"type":"string"},{"type":"null"}]},"storyAt":{"type":"string"},"results":{"type":"object","properties":{"clicks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"booked":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paidLabel":{"type":"string"}},"required":["clicks","booked","paidMinor","paidLabel"],"additionalProperties":false}},"required":["id","kind","title","line","createdAt","createdVia","createdBy","canceledAt","clicks","booked","paidMinor","paidLabel","targets","subject","locationId","caption","draftCaption","captionEdited","photos","formats","collaborators","at","storyAt","results"],"additionalProperties":false},"CustomerBookingPieces":{"type":"object","properties":{"on":{"type":"boolean","description":"The listing has its Pieces switch on."},"pieces":{"type":"array","items":{"$ref":"#/components/schemas/CustomerPiece"}},"stepNames":{"$ref":"#/components/schemas/PieceStepNames"},"pickupLine":{"anyOf":[{"type":"string"},{"type":"null"}]},"canAdd":{"type":"boolean","description":"Add your pieces is open: a confirmed or checked-in booking on a pieces listing, from its session's start until a piece goes past Made."},"room":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many more pieces the booking takes: 12 a spot, less those it has."},"reachedAt":{"type":"object","properties":{"made":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"inKiln":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"ready":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"pickedUp":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["made","inKiln","ready","pickedUp"],"additionalProperties":false,"description":"When each stage on the track was reached: Made is the first piece's; the rest the booking's last move there."}},"required":["on","pieces","stepNames","pickupLine","canAdd","room","reachedAt"],"additionalProperties":false,"example":{"on":true,"pieces":[{"id":"019a0000-0000-7000-8000-0000000002a2","label":"Giraffe","stage":"ready","addedBy":"customer","removable":false,"photos":[{"id":"019a0000-0000-7000-8000-0000000002c2","url":"https://private-media.example/pieces/b/p/photo.jpg?X-Amz-Expires=3600","width":1600,"height":1200}]}],"stepNames":{"inKiln":"In the kiln","ready":"Ready for pickup","pickedUp":"Picked up"},"pickupLine":"Usually ready in about a week. We keep pieces 30 days after they're ready.","canAdd":false,"room":23,"reachedAt":{"made":"2026-10-10T20:00:00.000Z","inKiln":"2026-10-11T15:00:00.000Z","ready":"2026-10-12T16:20:00.000Z","pickedUp":null}}},"CustomerPiece":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What it is — *Giraffe*. Null until someone names it."},"stage":{"$ref":"#/components/schemas/PieceStage"},"addedBy":{"type":"string","enum":["desk","customer"]},"removable":{"type":"boolean","description":"The customer added it and Add your pieces is still open: they may take it back off."},"photos":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"url":{"type":"string","format":"uri","description":"A signed read of the JPEG, good for an hour. Never stored or shared."},"width":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","url","width","height"],"additionalProperties":false},"description":"Signed reads good for an hour, the cover first."}},"required":["id","label","stage","addedBy","removable","photos"],"additionalProperties":false,"description":"One thing the customer made, as their booking page shows it.","example":{"id":"019a0000-0000-7000-8000-0000000002a2","label":"Giraffe","stage":"ready","addedBy":"customer","removable":false,"photos":[{"id":"019a0000-0000-7000-8000-0000000002c2","url":"https://private-media.example/pieces/b/p/photo.jpg?X-Amz-Expires=3600","width":1600,"height":1200}]}},"Terminal":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"businessId":{"$ref":"#/components/schemas/Uuid"},"locationId":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["waiting","paired"],"description":"`waiting` until a device scans its code."},"pairedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastSeenAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","businessId","locationId","name","status","pairedAt","lastSeenAt","createdAt"],"additionalProperties":false,"description":"A shared in-store device. Its credential can do one thing: accept a team member’s PIN.","example":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","businessId":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","locationId":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Front desk iPad","status":"paired","pairedAt":"2026-09-21T16:00:00.000Z","lastSeenAt":"2026-09-21T16:00:00.000Z","createdAt":"2026-09-21T16:00:00.000Z"}},"TerminalWithPairing":{"type":"object","properties":{"terminal":{"$ref":"#/components/schemas/Terminal"},"pairing":{"type":"object","properties":{"code":{"type":"string","description":"One use, ten minutes. Shown once."},"url":{"type":"string","description":"What the QR carries — the code rides in the fragment."},"expiresAt":{"type":"string"}},"required":["code","url","expiresAt"],"additionalProperties":false}},"required":["terminal","pairing"],"additionalProperties":false,"example":{"terminal":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","businessId":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","locationId":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Front desk iPad","status":"waiting","pairedAt":null,"lastSeenAt":null,"createdAt":"2026-09-21T16:00:00.000Z"},"pairing":{"code":"K7PM2XQ9","url":"https://placefull.ai/app/terminal#K7PM2XQ9","expiresAt":"2026-09-21T16:00:00.000Z"}}},"TerminalPaired":{"type":"object","properties":{"terminalToken":{"type":"string","description":"The device credential (`bt_…`). Returned once; good until the terminal is revoked."},"terminal":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"business":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"location":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}},"required":["terminalToken","terminal","business","location"],"additionalProperties":false,"example":{"terminalToken":"bt_…","terminal":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Front desk iPad"},"business":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Ash Street Yoga"},"location":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Ash Street"}}},"TerminalIdentity":{"type":"object","properties":{"terminal":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"business":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"location":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}},"required":["terminal","business","location"],"additionalProperties":false,"example":{"terminal":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Front desk iPad"},"business":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Ash Street Yoga"},"location":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Ash Street"}}},"TerminalSignedIn":{"type":"object","properties":{"sessionToken":{"type":"string","description":"An ordinary session bearer, pinned to the terminal’s business and capped at Front desk. Thirty idle minutes ends it."},"sessionExpiresAt":{"type":"string"},"person":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"displayName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","displayName"],"additionalProperties":false},"terminal":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"business":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"location":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}},"required":["sessionToken","sessionExpiresAt","person","terminal","business","location"],"additionalProperties":false,"example":{"sessionToken":"…","sessionExpiresAt":"2026-09-21T16:00:00.000Z","person":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","displayName":"Jane"},"terminal":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Front desk iPad"},"business":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Ash Street Yoga"},"location":{"id":"018f2c1a-7b3e-7c4d-9a10-5e2f6b7c8d90","name":"Ash Street"}}},"TrxPayoutList":{"type":"object","properties":{"payouts":{"type":"array","items":{"$ref":"#/components/schemas/TrxPayoutSummary"},"description":"Newest deposit first"},"notYetDeposited":{"type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Approved sales not in the bank yet: no batch, a batch still open or closed, or a settled batch with no deposit date stated"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units; their sum, less returns waiting with them"},"currency":{"type":"string"}},"required":["count","amount","currency"],"additionalProperties":false}},"required":["payouts","notYetDeposited"],"additionalProperties":false,"example":{"payouts":[{"batchGuid":"BATCH0000000000A","status":"deposited","watchingReason":null,"batchStatus":"settled","amount":124000,"oursAmount":124000,"otherAmount":null,"shared":false,"currency":"USD","depositDate":"2026-09-26","openedAt":"2026-09-25T07:00:00.000Z","settledAt":"2026-09-26T07:12:00.000Z","paymentCount":14,"refundCount":1,"reconciled":true,"reconcileDelta":0},{"batchGuid":"BATCH0000000000B","status":"watching","watchingReason":"unreconciled","batchStatus":"settled","amount":51500,"oursAmount":51465,"otherAmount":null,"shared":false,"currency":"USD","depositDate":"2026-09-27","openedAt":"2026-09-25T07:00:00.000Z","settledAt":"2026-09-26T07:12:00.000Z","paymentCount":3,"refundCount":0,"reconciled":false,"reconcileDelta":35}],"notYetDeposited":{"count":2,"amount":41200,"currency":"USD"}}},"TrxPayoutSummary":{"type":"object","properties":{"batchGuid":{"type":"string","description":"TRX's batch GUID"},"status":{"type":"string","enum":["batching","settled","deposit_expected","deposited","watching"],"description":"Batching while TRX holds it open or closed; settled once TRX says so but no deposit date is stated yet; deposit_expected while the stated deposit date is ahead; deposited once that date has come; watching when stuck — open too long, or settled and not matching our books (on a merchant account shared with legacy, only when the deposit is less than our bookings in it). Read as words (src/helpers/money-state.ts): batching = Pending; settled and deposit_expected = On the way; deposited = Deposited; watching = Watching."},"watchingReason":{"anyOf":[{"type":"string","enum":["unsettled","unreconciled"]},{"type":"null"}],"description":"Why it is watching, else null"},"batchStatus":{"type":"string","enum":["open","closed","settled"],"description":"TRX's own status word"},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minor units — TRX's net for a settled batch, our sales less returns until then; null before either. On a shared merchant account, always our part"},"oursAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units; Σ our sales − Σ our returns in the batch"},"otherAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minor units; on a shared merchant account, what the settled batch held from the other system (TRX's net − ours); null otherwise"},"shared":{"type":"boolean","description":"The merchant account is shared with the legacy system, so this row speaks for our part of the batch"},"currency":{"type":"string"},"depositDate":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"YYYY-MM-DD TRX claims the deposit lands. The bank is the last word."},"openedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"settledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Our sales in the batch"},"refundCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"reconciled":{"type":"boolean","description":"TRX's net equals Σ our sales − Σ our returns in it; on a shared merchant account, TRX's net is at least that"},"reconcileDelta":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minor units; what the batch misses by — 0 when reconciled, else TRX's net − ours; null until settled"}},"required":["batchGuid","status","watchingReason","batchStatus","amount","oursAmount","otherAmount","shared","currency","depositDate","openedAt","settledAt","paymentCount","refundCount","reconciled","reconcileDelta"],"additionalProperties":false,"example":{"batchGuid":"BATCH0000000000A","status":"deposited","watchingReason":null,"batchStatus":"settled","amount":124000,"oursAmount":124000,"otherAmount":null,"shared":false,"currency":"USD","depositDate":"2026-09-26","openedAt":"2026-09-25T07:00:00.000Z","settledAt":"2026-09-26T07:12:00.000Z","paymentCount":14,"refundCount":1,"reconciled":true,"reconcileDelta":0}},"TrxPayoutDetail":{"type":"object","properties":{"batchGuid":{"type":"string","description":"TRX's batch GUID"},"status":{"type":"string","enum":["batching","settled","deposit_expected","deposited","watching"],"description":"Batching while TRX holds it open or closed; settled once TRX says so but no deposit date is stated yet; deposit_expected while the stated deposit date is ahead; deposited once that date has come; watching when stuck — open too long, or settled and not matching our books (on a merchant account shared with legacy, only when the deposit is less than our bookings in it). Read as words (src/helpers/money-state.ts): batching = Pending; settled and deposit_expected = On the way; deposited = Deposited; watching = Watching."},"watchingReason":{"anyOf":[{"type":"string","enum":["unsettled","unreconciled"]},{"type":"null"}],"description":"Why it is watching, else null"},"batchStatus":{"type":"string","enum":["open","closed","settled"],"description":"TRX's own status word"},"amount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minor units — TRX's net for a settled batch, our sales less returns until then; null before either. On a shared merchant account, always our part"},"oursAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units; Σ our sales − Σ our returns in the batch"},"otherAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minor units; on a shared merchant account, what the settled batch held from the other system (TRX's net − ours); null otherwise"},"shared":{"type":"boolean","description":"The merchant account is shared with the legacy system, so this row speaks for our part of the batch"},"currency":{"type":"string"},"depositDate":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"YYYY-MM-DD TRX claims the deposit lands. The bank is the last word."},"openedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"settledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Our sales in the batch"},"refundCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"reconciled":{"type":"boolean","description":"TRX's net equals Σ our sales − Σ our returns in it; on a shared merchant account, TRX's net is at least that"},"reconcileDelta":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minor units; what the batch misses by — 0 when reconciled, else TRX's net − ours; null until settled"},"payments":{"type":"array","items":{"type":"object","properties":{"reference":{"type":"string","description":"TRX's reference GUID for the sale or return"},"kind":{"type":"string","enum":["sale","return"]},"paymentId":{"$ref":"#/components/schemas/Uuid"},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Who paid, as Payments activity labels them"},"item":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What was bought: listing · date, or the product; a cart payment lists its things, capped"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"cardBrand":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"depositDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["reference","kind","paymentId","customerName","item","amount","currency","cardBrand","cardLast4","createdAt","depositDate"],"additionalProperties":false}},"refunds":{"type":"array","items":{"type":"object","properties":{"reference":{"type":"string","description":"TRX's reference GUID for the sale or return"},"kind":{"type":"string","enum":["sale","return"]},"paymentId":{"$ref":"#/components/schemas/Uuid"},"customerName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Who paid, as Payments activity labels them"},"item":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What was bought: listing · date, or the product; a cart payment lists its things, capped"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"},"cardBrand":{"anyOf":[{"type":"string"},{"type":"null"}]},"cardLast4":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"depositDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["reference","kind","paymentId","customerName","item","amount","currency","cardBrand","cardLast4","createdAt","depositDate"],"additionalProperties":false}},"adjustments":{"type":"array","items":{"type":"object","properties":{"ledgerId":{"$ref":"#/components/schemas/Uuid"},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Signed minor units — a chargeback is negative"},"currency":{"type":"string"},"memo":{"anyOf":[{"type":"string"},{"type":"null"}]},"occurredAt":{"$ref":"#/components/schemas/Timestamp"}},"required":["ledgerId","amount","currency","memo","occurredAt"],"additionalProperties":false},"description":"Adjustments a platform admin attributed to this batch (a chargeback recorded by hand)"},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Σ payments − Σ refunds + Σ adjustments — the receipt total, ours"}},"required":["batchGuid","status","watchingReason","batchStatus","amount","oursAmount","otherAmount","shared","currency","depositDate","openedAt","settledAt","paymentCount","refundCount","reconciled","reconcileDelta","payments","refunds","adjustments","total"],"additionalProperties":false,"example":{"batchGuid":"BATCH0000000000A","status":"deposited","watchingReason":null,"batchStatus":"settled","amount":124000,"oursAmount":124000,"otherAmount":null,"shared":false,"currency":"USD","depositDate":"2026-09-26","openedAt":"2026-09-25T07:00:00.000Z","settledAt":"2026-09-26T07:12:00.000Z","paymentCount":14,"refundCount":1,"reconciled":true,"reconcileDelta":0,"payments":[{"reference":"SALE00000000001","kind":"sale","paymentId":"550e8400-e29b-41d4-a716-446655440009","customerName":"F. HOLT","item":"Wheel Basics · Sep 25","amount":5000,"currency":"USD","cardBrand":"Visa","cardLast4":"4242","createdAt":"2026-09-25T15:04:00.000Z","depositDate":"2026-09-26"}],"refunds":[{"reference":"RET000000000001","kind":"return","paymentId":"550e8400-e29b-41d4-a716-446655440009","customerName":"F. HOLT","item":"Wheel Basics · Sep 25","amount":500,"currency":"USD","cardBrand":"Visa","cardLast4":"4242","createdAt":"2026-09-25T16:10:00.000Z","depositDate":"2026-09-26"}],"adjustments":[],"total":4500}},"TrxStatementList":{"type":"object","properties":{"statements":{"type":"array","items":{"$ref":"#/components/schemas/TrxStatementSummary"},"description":"Newest first"}},"required":["statements"],"additionalProperties":false,"example":{"statements":[{"statementDate":"2026-08-31","clientId":"412","dba":"Ash Street Yoga","feeTotal":4850,"currency":"USD","depositCount":21,"journaled":true,"journalSkipReason":null}]}},"TrxStatementSummary":{"type":"object","properties":{"statementDate":{"type":"string","description":"YYYY-MM-DD"},"clientId":{"type":"string"},"dba":{"anyOf":[{"type":"string"},{"type":"null"}]},"feeTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units; Σ the statement's fee lines — TRX's number"},"currency":{"type":"string"},"depositCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"journaled":{"type":"boolean","description":"Posted once as expense.trx_fees against the bank on its statement date"},"journalSkipReason":{"anyOf":[{"type":"string","enum":["shared_account"]},{"type":"null"}],"description":"Why the fees were kept out of the journal: a shared merchant account is billed for the other system too. Null otherwise"}},"required":["statementDate","clientId","dba","feeTotal","currency","depositCount","journaled","journalSkipReason"],"additionalProperties":false,"example":{"statementDate":"2026-08-31","clientId":"412","dba":"Ash Street Yoga","feeTotal":4850,"currency":"USD","depositCount":21,"journaled":true,"journalSkipReason":null}},"TrxStatementDetail":{"type":"object","properties":{"statementDate":{"type":"string","description":"YYYY-MM-DD"},"clientId":{"type":"string"},"dba":{"anyOf":[{"type":"string"},{"type":"null"}]},"feeTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Minor units; Σ the statement's fee lines — TRX's number"},"currency":{"type":"string"},"depositCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"journaled":{"type":"boolean","description":"Posted once as expense.trx_fees against the bank on its statement date"},"journalSkipReason":{"anyOf":[{"type":"string","enum":["shared_account"]},{"type":"null"}],"description":"Why the fees were kept out of the journal: a shared merchant account is billed for the other system too. Null otherwise"},"deposits":{"type":"array","items":{"type":"object","properties":{"tranDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"approvedAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastFour":{"anyOf":[{"type":"string"},{"type":"null"}]},"referenceNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["tranDate","approvedAmount","lastFour","referenceNumber"],"additionalProperties":false}},"cardPlans":{"type":"array","items":{"type":"object","properties":{"planCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"saleCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"saleAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"creditCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"creditAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"netSaleAmount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"averageTicket":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"discountRatePercent":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountRateItem":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"discountTotal":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["planCode","saleCount","saleAmount","creditCount","creditAmount","netSaleAmount","averageTicket","discountRatePercent","discountRateItem","discountTotal"],"additionalProperties":false}},"fees":{"type":"array","items":{"type":"object","properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["description","count","amount","total"],"additionalProperties":false},"description":"The statement's fee table, as TRX gave it"}},"required":["statementDate","clientId","dba","feeTotal","currency","depositCount","journaled","journalSkipReason","deposits","cardPlans","fees"],"additionalProperties":false,"example":{"statementDate":"2026-08-31","clientId":"412","dba":"Ash Street Yoga","feeTotal":4850,"currency":"USD","depositCount":21,"journaled":true,"journalSkipReason":null,"deposits":[{"tranDate":"2026-08-03","approvedAmount":124000,"lastFour":"4242","referenceNumber":"900012345"}],"cardPlans":[{"planCode":"VISA","saleCount":40,"saleAmount":210000,"creditCount":2,"creditAmount":6000,"netSaleAmount":204000,"averageTicket":5250,"discountRatePercent":2.65,"discountRateItem":10,"discountTotal":5806}],"fees":[{"description":"Monthly service fee","count":1,"amount":1500,"total":1500},{"description":"Transaction fee","count":67,"amount":50,"total":3350}]}},"SignupWaitlistResult":{"type":"object","properties":{"joined":{"type":"boolean","const":true}},"required":["joined"],"additionalProperties":false},"ImageFrameOutput":{"type":"object","properties":{"wide":{"$ref":"#/components/schemas/ShapeFrameOutput"},"square":{"$ref":"#/components/schemas/ShapeFrameOutput"}},"additionalProperties":false,"example":{"square":{"fit":"fill","x":0.5,"y":0.32,"zoom":1.6,"backdrop":"blur"}}},"ShapeFrameOutput":{"type":"object","properties":{"fit":{"type":"string","enum":["fill","whole"]},"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1},"zoom":{"type":"number","minimum":0.25,"maximum":4},"backdrop":{"type":"string","enum":["blur","color"]}},"required":["fit","x","y","zoom","backdrop"],"additionalProperties":false,"example":{"fit":"fill","x":0.5,"y":0.32,"zoom":1.6,"backdrop":"blur"}},"BookingImportTimeMappingOutput":{"type":"object","properties":{"zone":{"type":"string","description":"IANA zone for times that name none (Times are in)."},"dayFirst":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Day/month order; null lets the column decide."},"format":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A pattern from the known list, tried first; null for none."}},"required":["zone","dayFirst","format"],"additionalProperties":false},"StudioWordsOutput":{"type":"object","properties":{"instructor":{"description":"What customers see your instructors called. Default: instructor.","type":"string","enum":["instructor","coach","teacher","trainer","guide"]}},"additionalProperties":false,"example":{"instructor":"coach"}},"StorefrontThemeOutput":{"type":"object","properties":{"accent":{"description":"Customer-facing CTA color for this location’s pages and emails","anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"paper":{"description":"Page background hex. Ink and supporting tokens are derived so body text meets AA.","anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"null"}]},"ground":{"type":"string","enum":["paper","cream","stone","sage","ink"]},"type":{"type":"string","enum":["sans","serif","soft","editorial"]},"buttons":{"type":"string","enum":["pill","rounded","square","outline"]},"corners":{"type":"string","enum":["sharp","soft","round"]},"surface":{"type":"string","enum":["flat","raised","lined"]},"hero":{"type":"string","enum":["split","bleed","type"]},"header":{"type":"string","enum":["plain","bar","overlay"]},"display":{"type":"string","enum":["quiet","standard","bold"]}},"additionalProperties":false,"example":{}},"InlineScheduleDraftOutput":{"type":"object","properties":{"freq":{"type":"string","enum":["daily","weekly","monthly","dates"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"byWeekday":{"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"dates":{"type":"array","items":{"type":"string"}},"startTime":{"type":"string"},"startDate":{"type":"string"},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sessionLengthMinutes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"until":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["freq","interval","byWeekday","dates","startTime","startDate","durationMinutes","sessionLengthMinutes","until"],"additionalProperties":false},"FeatureOverridesOutput":{"type":"object","properties":{"grant":{"type":"array","items":{"type":"string"}},"revoke":{"type":"array","items":{"type":"string"}}},"required":["grant","revoke"],"additionalProperties":false,"example":{"grant":["booking.manage"],"revoke":[]}},"PieceShelvesOutput":{"type":"object","properties":{"shelves":{"maxItems":100,"type":"array","items":{"type":"string","maxLength":12},"description":"The location's shelf IDs in its order: at most 100 of at most 12 characters, each once."}},"required":["shelves"],"additionalProperties":false,"example":{"shelves":["A1","A2","A3","B1","B2","B3"]}}},"parameters":{"BusinessIdParam":{"in":"path","name":"businessId","schema":{"param":{"id":"BusinessIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"AccountingCategoryParam":{"in":"path","name":"category","schema":{"type":"string"},"required":true},"JournalBatchIdParam":{"in":"path","name":"batchId","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"required":true},"LocationOwnerIdParam":{"in":"path","name":"id","schema":{"param":{"id":"LocationOwnerIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"CartTokenParam":{"in":"path","name":"token","schema":{"type":"string"},"required":true},"CustomerIdParam":{"in":"path","name":"customerId","schema":{"param":{"id":"CustomerIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"AssetIdParam":{"in":"path","name":"id","schema":{"param":{"id":"AssetIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"ListingIdParam":{"in":"path","name":"id","schema":{"param":{"id":"ListingIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"ResourceIdParam":{"in":"path","name":"id","schema":{"param":{"id":"ResourceIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"InstructorIdParam":{"in":"path","name":"id","schema":{"param":{"id":"InstructorIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"MembershipPlanIdParam":{"in":"path","name":"id","schema":{"param":{"id":"MembershipPlanIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"BookingImportIdParam":{"in":"path","name":"importId","schema":{"param":{"id":"BookingImportIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"BookingImportIssueIdParam":{"in":"path","name":"issueId","schema":{"param":{"id":"BookingImportIssueIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"BusinessIdPathParam":{"in":"path","name":"id","schema":{"param":{"id":"BusinessIdPathParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"ApiKeyIdParam":{"in":"path","name":"id","schema":{"param":{"id":"ApiKeyIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"BookingIdParam":{"in":"path","name":"bookingId","schema":{"param":{"id":"BookingIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"LocationIdParam":{"in":"path","name":"locationId","schema":{"param":{"id":"LocationIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"EnrollmentIdParam":{"in":"path","name":"enrollmentId","schema":{"param":{"id":"EnrollmentIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"OccurrenceIdParam":{"in":"path","name":"occurrenceId","schema":{"type":"string"},"required":true},"EntryIdParam":{"in":"path","name":"entryId","schema":{"param":{"id":"EntryIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"ChannelIdParam":{"in":"path","name":"channelId","schema":{"param":{"id":"ChannelIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"ExternalRefParam":{"in":"path","name":"externalRef","schema":{"type":"string","minLength":1},"required":true},"ClaimIdParam":{"in":"path","name":"claimId","schema":{"param":{"id":"ClaimIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PaymentIdParam":{"in":"path","name":"paymentId","schema":{"param":{"id":"PaymentIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PlanIdParam":{"in":"path","name":"planId","schema":{"param":{"id":"PlanIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"MembershipIdParam":{"in":"path","name":"membershipId","schema":{"param":{"id":"MembershipIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"TaxRateIdParam":{"in":"path","name":"id","schema":{"param":{"id":"TaxRateIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"RevenueCategoryIdParam":{"in":"path","name":"id","schema":{"param":{"id":"RevenueCategoryIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"CustomerListIdParam":{"in":"path","name":"id","schema":{"param":{"id":"CustomerListIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"MessageIdParam":{"in":"path","name":"id","schema":{"param":{"id":"MessageIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"DiscountIdParam":{"in":"path","name":"id","schema":{"param":{"id":"DiscountIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"CalendarConnectionIdParam":{"in":"path","name":"connectionId","schema":{"param":{"id":"CalendarConnectionIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"SessionIdParam":{"in":"path","name":"sessionId","schema":{"param":{"id":"SessionIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PersonIdParam":{"in":"path","name":"id","schema":{"param":{"id":"PersonIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"SeriesIdParam":{"in":"path","name":"id","schema":{"param":{"id":"SeriesIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"UserRoleIdParam":{"in":"path","name":"id","schema":{"param":{"id":"UserRoleIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"CartItemIdParam":{"in":"path","name":"itemId","schema":{"param":{"id":"CartItemIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"ImageIdParam":{"in":"path","name":"id","schema":{"param":{"id":"ImageIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"JourneyStepIdParam":{"in":"path","name":"stepId","schema":{"param":{"id":"JourneyStepIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"OfferingIdParam":{"in":"path","name":"offeringId","schema":{"param":{"id":"OfferingIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"BookingStepIdParam":{"in":"path","name":"bookingStepId","schema":{"param":{"id":"BookingStepIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PerformanceReportParam":{"in":"path","name":"report","schema":{"type":"string"},"required":true},"PieceIdParam":{"in":"path","name":"pieceId","schema":{"param":{"id":"PieceIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PiecePhotoIdParam":{"in":"path","name":"photoId","schema":{"param":{"id":"PiecePhotoIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"LegacyMirrorIdParam":{"in":"path","name":"mirrorId","schema":{"param":{"id":"LegacyMirrorIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PhoneCallIdParam":{"in":"path","name":"callId","schema":{"param":{"id":"PhoneCallIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PhoneThreadIdParam":{"in":"path","name":"threadId","schema":{"param":{"id":"PhoneThreadIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PhoneTextIdParam":{"in":"path","name":"textId","schema":{"param":{"id":"PhoneTextIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"PhoneTextMediaIndexParam":{"in":"path","name":"index","schema":{"type":"string"},"required":true},"ProductIdParam":{"in":"path","name":"productId","schema":{"param":{"id":"ProductIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"VariantIdParam":{"in":"path","name":"variantId","schema":{"param":{"id":"VariantIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"OrderLineIdParam":{"in":"path","name":"orderLineId","schema":{"param":{"id":"OrderLineIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"ReportPaymentIdParam":{"in":"path","name":"paymentId","schema":{"description":"Our payment id","param":{"id":"ReportPaymentIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"Our payment id"},"DepositIdParam":{"in":"path","name":"depositId","schema":{"type":"string","description":"A Stripe payout id (`po_…`) or a TRX batch GUID"},"required":true,"description":"A Stripe payout id (`po_…`) or a TRX batch GUID"},"StatementMonthParam":{"in":"path","name":"month","schema":{"type":"string","description":"A closed month, `YYYY-MM`"},"required":true,"description":"A closed month, `YYYY-MM`"},"PayoutIdParam":{"in":"path","name":"payoutId","schema":{"type":"string"},"required":true},"ScheduleIdParam":{"in":"path","name":"id","schema":{"param":{"id":"ScheduleIdParam"},"$ref":"#/components/schemas/Uuid"},"required":true,"description":"UUID identifier"},"TrxBatchGuidParam":{"in":"path","name":"batchGuid","schema":{"type":"string","description":"TRX's batch GUID"},"required":true,"description":"TRX's batch GUID"},"TrxStatementDateParam":{"in":"path","name":"statementDate","schema":{"type":"string","description":"YYYY-MM-DD"},"required":true,"description":"YYYY-MM-DD"}},"securitySchemes":{"sessionBearer":{"type":"http","scheme":"bearer","bearerFormat":"session","description":"Passwordless session token returned by POST /auth/verify"},"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"bk_","description":"Machine API key prefixed with `bk_`. Sent as `Authorization: Bearer bk_…`."}}}}