{"openapi":"3.1.0","info":{"title":"Maison API","description":"AI-powered hotel concierge platform API. Exposes REST, A2A (Agent-to-Agent), and MCP (Model Context Protocol) interfaces over the same business logic.","version":"1.0.0","contact":{"name":"Maison Labs","url":"https://maison-labs.com"}},"servers":[{"url":"https://maison-labs.com","description":"Production"}],"tags":[{"name":"REST API","description":"Chat sessions and client config"},{"name":"Client API","description":"Client-specific message translations and field configuration"},{"name":"Auth","description":"Session authentication"},{"name":"API Keys","description":"API key lifecycle management"},{"name":"Clients","description":"Client (tenant) CRUD management"},{"name":"A2A","description":"Agent-to-Agent protocol (JSON-RPC 2.0)"},{"name":"MCP","description":"Model Context Protocol (Streamable HTTP)"},{"name":"Tools","description":"Website and integration diagnostic tools"},{"name":"Diagnostic","description":"Agentic site diagnostic runs and follow-up chat"},{"name":"Webhooks","description":"Inbound integration callbacks from external platforms (Meta Instagram). These are transport-layer endpoints, exempt from A2A/MCP interface parity."},{"name":"Users","description":"User account management"},{"name":"Roles","description":"Role-based access control management"},{"name":"Features","description":"Feature flag and permission feature management"},{"name":"User Groups","description":"User group management and membership control"},{"name":"Settings","description":"Client-scoped settings: regions, departments, and tags"},{"name":"Legacy","description":"Temporary backward-compatibility shims for legacy/business-console and legacy/pipeline-tasks. SCHEDULED FOR REMOVAL — do not build new clients against these endpoints. See docs/legacy-endpoints.md."}],"paths":{"/api/translations":{"get":{"tags":["Client API"],"operationId":"getTranslations","summary":"Get client translations","description":"Fetch UI translations for a client. Keys and locales can be specified via headers or query params. Supports JSONP via `tcb` query param.","parameters":[{"name":"x-client-id","in":"header","required":false,"schema":{"type":"string"},"description":"Client (tenant) UUID"},{"name":"x-translation-keys","in":"header","schema":{"type":"string"},"description":"Comma-separated translation keys, or `*` for all"},{"name":"x-translation-locales","in":"header","schema":{"type":"string"},"description":"Comma-separated locales, or `*` for all"},{"name":"clientid","in":"query","schema":{"type":"string"}},{"name":"keys","in":"query","schema":{"type":"string"}},{"name":"locales","in":"query","schema":{"type":"string"}},{"name":"tcb","in":"query","schema":{"type":"string"},"description":"JSONP callback name"}],"responses":{"200":{"description":"Translations object (JSON or JSONP)","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Missing client ID or translation keys","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/client/fields":{"get":{"tags":["Client API"],"operationId":"getClientFields","summary":"Get client config fields","description":"Fetch specific fields from a client's configuration.","parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"},"description":"Client (tenant) UUID"},{"name":"x-client-fields","in":"header","required":true,"schema":{"type":"string"},"description":"Comma-separated field paths (e.g. `hotelConfig.name,clientAssets.icon`)"},{"name":"x-client-locale","in":"header","schema":{"type":"string"},"description":"Locale override"}],"responses":{"200":{"description":"Requested fields","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Missing client ID or fields","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/me":{"get":{"tags":["Auth"],"operationId":"getMe","summary":"Get current user profile and permissions","description":"Returns the authenticated user's userId, email, and flattened permission set. Accepts session cookie or Authorization: Bearer header.","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Authenticated user profile","content":{"application/json":{"schema":{"type":"object","required":["userId","email","permissions","isMaisonAdmin"],"properties":{"userId":{"type":"string"},"email":{"type":"string"},"permissions":{"type":"array","items":{"type":"string"},"description":"Flattened permission strings: FEATURE:PERM or FEATURE:PERM:clientId"},"isMaisonAdmin":{"type":"boolean","description":"True when the user has global EXECUTE on ALL features (MaisonAdmin role)."}}}}}},"401":{"description":"Not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to fetch user profile","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/message":{"get":{"tags":["REST API"],"operationId":"getMessageSession","summary":"Get or create chat session","description":"Returns the current session (or creates one) for the given client.","parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"},"description":"Client (tenant) UUID"}],"responses":{"200":{"description":"Session with message history","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}}}}}}},"400":{"description":"Invalid client ID or session","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Session does not exist","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["REST API"],"operationId":"postMessage","summary":"Send a chat message","description":"Submit a user query. Normally returns 202 Accepted immediately and delivers the assistant reply via the real-time events channel. Requests marked with the `x-test-session: true` header (the prompt-test / golden-FAQ worker, a backend job that is not a real-time subscriber) instead receive a synchronous 200 with the assistant reply in the body.","parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"},"description":"Client (tenant) UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryBody"}}}},"responses":{"200":{"description":"Synchronous assistant reply (test-session requests only — see the `x-test-session` header).","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"datetime":{"type":"number"},"type":{"type":"string"},"context":{"type":"array","items":{"type":"string"}}}}}}},"202":{"description":"Query accepted for async processing","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ack"]},"sessionId":{"type":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/auth/":{"get":{"tags":["Auth"],"operationId":"checkAuth","summary":"Check session authentication","description":"Returns 200 if the caller has a valid session; 401 otherwise. Returns user email for authenticated sessions.","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Authenticated — returns user info","content":{"application/json":{"schema":{"type":"object","properties":{"authenticated":{"type":"boolean"},"email":{"type":"string","format":"email"},"userId":{"type":"string"}}}}}},"401":{"description":"Not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/auth/login":{"post":{"tags":["Auth"],"operationId":"login","summary":"Authenticate with credentials","description":"Authenticate with email and password. Auth payload must be base64(email:password) to avoid exposing the password in transit. On success, sets a session cookie scoped to .maison-labs.com.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username","auth"],"properties":{"username":{"type":"string","format":"email","description":"User email address"},"auth":{"type":"string","description":"base64(email:password)"}}}}}},"responses":{"200":{"description":"Authenticated — session cookie set"},"400":{"description":"Missing username or auth","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Invalid credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"User must reset their password before logging in (admin-flagged force_reset_password); no session is issued.","content":{"application/json":{"schema":{"type":"object","required":["forceReset","email"],"properties":{"error":{"type":"string"},"forceReset":{"type":"boolean"},"email":{"type":"string","format":"email"}}}}}}}}},"/auth/logout":{"post":{"tags":["Auth"],"operationId":"logout","summary":"Log out and revoke session","description":"Clears the session cookie and revokes the Firebase refresh token. Always returns 200, even if token revocation fails.","responses":{"200":{"description":"Logged out — session cookie cleared"}}}},"/auth/resetpasswordcode":{"post":{"tags":["Auth"],"operationId":"requestResetPasswordCode","summary":"Request a TOTP password reset code via email","description":"Generates a stateless TOTP reset code and sends it to the user's registered email address. Always returns 200 regardless of whether the account exists (no account enumeration). Resend is throttled to one code per 30 seconds per account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nonce"],"properties":{"email":{"type":"string","format":"email","description":"Email address of the account to reset. Mutually exclusive with userId."},"userId":{"type":"string","format":"uuid","description":"UUID of the user to reset. Mutually exclusive with email."},"nonce":{"type":"string","minLength":16,"description":"Caller-generated random string (≥16 chars). Must be re-sent verbatim to /auth/resetpassword. Ties the code to this specific reset session."}}}}}},"responses":{"200":{"description":"Code sent (or silently skipped when account does not match any registration)","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid request — e.g. both email and userId supplied","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"No identifier supplied and no active session","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/auth/resetpassword":{"post":{"tags":["Auth"],"operationId":"resetPasswordWithCode","summary":"Verify TOTP reset code and set a new password","description":"Verifies the 6-digit TOTP code (from /auth/resetpasswordcode) against the supplied nonce and sets the new password via Firebase Admin SDK. Verify attempts are rate-limited to 5 per minute per account+IP to prevent brute-force.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nonce","code","newPassword"],"properties":{"email":{"type":"string","format":"email","description":"Email address of the account. Mutually exclusive with userId."},"userId":{"type":"string","format":"uuid","description":"UUID of the user. Mutually exclusive with email."},"nonce":{"type":"string","minLength":16,"description":"The same nonce sent to /auth/resetpasswordcode."},"code":{"type":"string","pattern":"^\\d{6}$","description":"6-digit TOTP code received via email."},"newPassword":{"type":"string","minLength":8,"description":"New password to set (minimum 8 characters)."}}}}}},"responses":{"200":{"description":"Password updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid or expired code, or malformed request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Too many verify attempts — try again later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/auth/users/{id}/invite/accept":{"post":{"tags":["Users","Auth"],"operationId":"acceptInvite","summary":"Accept invitation and create user account","description":"Verifies the invitation for the given user ID, sets the user's password via Firebase, and returns a session cookie. The invite link is single-use; subsequent calls return 400.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the invited user"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password","first_name","last_name"],"properties":{"email":{"type":"string","format":"email","description":"User email address (must match the invitation)"},"password":{"type":"string","description":"Password to set for the new account"},"first_name":{"type":"string","description":"User's first name"},"last_name":{"type":"string","description":"User's last name"}}}}}},"responses":{"200":{"description":"Invitation accepted — session cookie set (HttpOnly, Secure, SameSite=Lax)","content":{"application/json":{"schema":{"type":"object","required":["session","email"],"properties":{"session":{"type":"string","description":"Session token"},"email":{"type":"string","format":"email"}}}}}},"400":{"description":"Invalid or already-accepted invitation","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Invited user not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Account already exists for this email","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/user/apikey":{"put":{"tags":["API Keys"],"operationId":"createApiKey","summary":"Create API key","description":"Generate a new HMAC-signed API key. The full key is returned once and cannot be recovered. Requires session auth (API key auth is rejected).","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-user-id","in":"header","schema":{"type":"string"},"description":"Target user UUID. If omitted, creates for self. Requires ApiKeys WRITE permission for other users."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateBody"}}}},"responses":{"201":{"description":"API key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"API key auth used, or insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Target user not found or disabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/user/apikey/{id}":{"delete":{"tags":["API Keys"],"operationId":"deleteApiKey","summary":"Disable API key","description":"Disable an API key by its database ID. Requires session auth. Deleting another user's key requires ApiKeys WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"API key database UUID"}],"responses":{"200":{"description":"API key disabled","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"API key auth used, or insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"API key not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/.well-known/agent.json":{"get":{"tags":["A2A"],"operationId":"getAgentCard","summary":"A2A agent card","description":"Discovery endpoint for the A2A protocol. Returns capabilities, skills, and auth requirements.","responses":{"200":{"description":"Agent card","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentCard"}}}}}}},"/a2a":{"post":{"tags":["A2A"],"operationId":"a2aDispatch","summary":"A2A JSON-RPC endpoint","description":"JSON-RPC 2.0 endpoint for A2A protocol. Methods: `tasks/send`, `tasks/get`, `tasks/cancel`. Requires API key + client ID.","security":[{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"},"description":"Client (tenant) UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"JSON-RPC response (success or error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}}}}},"/mcp":{"post":{"tags":["MCP"],"operationId":"mcpPost","summary":"MCP request handler","description":"Streamable HTTP transport for MCP. Handles initialize, tools/list, tools/call, and other JSON-RPC messages. Include `mcp-session-id` header for established sessions.","security":[{"apiKey":[]}],"parameters":[{"name":"mcp-session-id","in":"header","schema":{"type":"string"},"description":"Session ID returned from initialize. Omit for the initial request."}],"requestBody":{"required":true,"description":"JSON-RPC 2.0 message. For `tools/call`, the `params.arguments` object conforms to one of the MCP tool schemas (see components/schemas for Mcp*Params). Core schemas: McpQueryHotelParams, McpGetSessionParams, McpCreateSessionParams, McpGetClientInfoParams, McpListTranslationsParams. Management schemas: McpListClientsParams, McpGetClientParams, McpCreateClientParams, McpUpdateClientParams, McpDisableClientParams, McpListUsersParams, McpGetUserParams, McpInviteUserParams, McpUpdateUserParams, McpDisableUserParams, McpReinviteUserParams, McpForceResetUserParams, McpGetUserActivityParams, McpListRolesParams, McpGetRoleParams, McpCreateRoleParams, McpUpdateRoleParams, McpDisableRoleParams, McpAddRolePolicyParams, McpRemoveRolePolicyParams, McpGetRoleUsersParams, McpGetRoleGroupsParams, McpListFeaturesParams, McpCreateFeatureParams, McpUpdateFeatureParams, McpDeprecateFeatureParams, McpListUserGroupsParams, McpGetUserGroupParams, McpCreateUserGroupParams, McpUpdateUserGroupParams, McpDeleteUserGroupParams, McpUpdateGroupMembersParams, McpUpdateGroupRolesParams, McpListRegionsParams, McpCreateRegionParams, McpUpdateRegionParams, McpDeleteRegionParams, McpListDepartmentsParams, McpCreateDepartmentParams, McpUpdateDepartmentParams, McpDeleteDepartmentParams, McpListTagsParams, McpCreateTagParams, McpUpdateTagParams, McpDeleteTagParams, McpListClientPipelineTasksParams, McpStopClientPipelineTaskParams.","content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","id","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"number"}]},"method":{"type":"string","description":"MCP method (e.g. initialize, tools/list, tools/call)"},"params":{"type":"object","properties":{"name":{"type":"string","description":"Tool name (for tools/call)","enum":["query_hotel","get_session","create_session","get_client_info","list_translations"]},"arguments":{"oneOf":[{"$ref":"#/components/schemas/McpQueryHotelParams"},{"$ref":"#/components/schemas/McpGetSessionParams"},{"$ref":"#/components/schemas/McpCreateSessionParams"},{"$ref":"#/components/schemas/McpGetClientInfoParams"},{"$ref":"#/components/schemas/McpListTranslationsParams"},{"$ref":"#/components/schemas/McpListClientsParams"},{"$ref":"#/components/schemas/McpGetClientParams"},{"$ref":"#/components/schemas/McpCreateClientParams"},{"$ref":"#/components/schemas/McpUpdateClientParams"},{"$ref":"#/components/schemas/McpDisableClientParams"},{"$ref":"#/components/schemas/McpListUsersParams"},{"$ref":"#/components/schemas/McpGetUserParams"},{"$ref":"#/components/schemas/McpInviteUserParams"},{"$ref":"#/components/schemas/McpUpdateUserParams"},{"$ref":"#/components/schemas/McpDisableUserParams"},{"$ref":"#/components/schemas/McpReinviteUserParams"},{"$ref":"#/components/schemas/McpForceResetUserParams"},{"$ref":"#/components/schemas/McpGetUserActivityParams"},{"$ref":"#/components/schemas/McpListRolesParams"},{"$ref":"#/components/schemas/McpGetRoleParams"},{"$ref":"#/components/schemas/McpCreateRoleParams"},{"$ref":"#/components/schemas/McpUpdateRoleParams"},{"$ref":"#/components/schemas/McpDisableRoleParams"},{"$ref":"#/components/schemas/McpAddRolePolicyParams"},{"$ref":"#/components/schemas/McpRemoveRolePolicyParams"},{"$ref":"#/components/schemas/McpGetRoleUsersParams"},{"$ref":"#/components/schemas/McpGetRoleGroupsParams"},{"$ref":"#/components/schemas/McpListFeaturesParams"},{"$ref":"#/components/schemas/McpCreateFeatureParams"},{"$ref":"#/components/schemas/McpUpdateFeatureParams"},{"$ref":"#/components/schemas/McpDeprecateFeatureParams"},{"$ref":"#/components/schemas/McpListUserGroupsParams"},{"$ref":"#/components/schemas/McpGetUserGroupParams"},{"$ref":"#/components/schemas/McpCreateUserGroupParams"},{"$ref":"#/components/schemas/McpUpdateUserGroupParams"},{"$ref":"#/components/schemas/McpDeleteUserGroupParams"},{"$ref":"#/components/schemas/McpUpdateGroupMembersParams"},{"$ref":"#/components/schemas/McpUpdateGroupRolesParams"},{"$ref":"#/components/schemas/McpListRegionsParams"},{"$ref":"#/components/schemas/McpCreateRegionParams"},{"$ref":"#/components/schemas/McpUpdateRegionParams"},{"$ref":"#/components/schemas/McpDeleteRegionParams"},{"$ref":"#/components/schemas/McpListDepartmentsParams"},{"$ref":"#/components/schemas/McpCreateDepartmentParams"},{"$ref":"#/components/schemas/McpUpdateDepartmentParams"},{"$ref":"#/components/schemas/McpDeleteDepartmentParams"},{"$ref":"#/components/schemas/McpListTagsParams"},{"$ref":"#/components/schemas/McpCreateTagParams"},{"$ref":"#/components/schemas/McpUpdateTagParams"},{"$ref":"#/components/schemas/McpDeleteTagParams"},{"$ref":"#/components/schemas/McpListClientPipelineTasksParams"},{"$ref":"#/components/schemas/McpStopClientPipelineTaskParams"}]}}}}}}}},"responses":{"200":{"description":"JSON-RPC response or SSE stream","content":{"application/json":{"schema":{"type":"object"}},"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"get":{"tags":["MCP"],"operationId":"mcpSse","summary":"MCP SSE stream","description":"Server-Sent Events stream for MCP server notifications. Requires established session.","security":[{"apiKey":[]}],"parameters":[{"name":"mcp-session-id","in":"header","required":true,"schema":{"type":"string"},"description":"Established session ID"}],"responses":{"200":{"description":"SSE stream","content":{"text/event-stream":{"schema":{"type":"string"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["MCP"],"operationId":"mcpClose","summary":"Close MCP session","description":"End an MCP session and release resources.","security":[{"apiKey":[]}],"parameters":[{"name":"mcp-session-id","in":"header","required":true,"schema":{"type":"string"},"description":"Session ID to close"}],"responses":{"200":{"description":"Session closed"},"404":{"description":"Session not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients":{"get":{"tags":["Clients"],"operationId":"listClients","summary":"List clients","description":"Return a paginated, searchable, sortable list of active clients. Requires session auth and clients:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of clients to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against client name, description, and website domain"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","disabled","all"]},"description":"Filter by lifecycle status. `active` (default) excludes disabled clients, `disabled` shows only disabled, `all` returns both."},{"name":"order_by","in":"query","schema":{"type":"string","enum":["name","created_date","website_id","demo_client","last_scraped_date","ai_visibility_schedule"],"default":"created_date"},"description":"Column to sort by"},{"name":"sort","in":"query","schema":{"type":"string","enum":["ASC","DESC"],"default":"DESC"},"description":"Sort direction"}],"responses":{"200":{"description":"Paginated list of clients","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientListResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Clients"],"operationId":"createClient","summary":"Create client","description":"Create a new client record. Requires session auth and clients:WRITE permission.","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientBody"}}}},"responses":{"201":{"description":"Client created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Client"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/summary":{"get":{"tags":["Clients"],"operationId":"getClientsSummary","summary":"Get clients summary","description":"Return aggregate counts across all active clients. Requires session auth and clients:READ permission.","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Aggregate client counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientsSummaryResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/metrics":{"get":{"tags":["Clients"],"operationId":"getClientMetrics","summary":"Get client Overview metrics","description":"Returns metrics used by the Client Overview tab. Today this is a stub that returns an empty metrics object; shape will stay stable while fields are added in later features.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"Client metrics (empty for now)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientMetricsResponse"}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/website/rescrape":{"post":{"tags":["Clients"],"operationId":"rescrapeClientWebsite","summary":"Trigger a fresh website scrape","description":"Schedules a fresh scrape of the client's primary website. Returns immediately; the response indicates whether the task was accepted for processing (enqueued=true) or recorded but not yet dispatched (enqueued=false, typically in non-production environments).","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescrapeClientBody"}}}},"responses":{"202":{"description":"Scrape session recorded and (optionally) enqueued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescrapeClientResponse"}}}},"400":{"description":"Invalid client id or body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Client has no website to rescrape or is disabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/demosite":{"post":{"tags":["Clients"],"operationId":"createClientDemoSite","summary":"Create or recreate the demo preview site","description":"Generates or refreshes a preview demo site for the client that embeds the client's website and the Maison chat widget. Returns the public URL of the created site. Returns 503 when the preview-site feature is not configured in this environment.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemoSiteBody"}}}},"responses":{"201":{"description":"Demo site created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemoSiteResponse"}}}},"400":{"description":"Invalid client id or body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Preview-site not configured in this environment","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}":{"get":{"tags":["Clients"],"operationId":"getClient","summary":"Get client by ID","description":"Fetch a single client record by UUID. Requires session auth and clients:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"Client record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Client"}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Clients"],"operationId":"updateClient","summary":"Update client","description":"Partially update a client record. All body fields are optional. Requires session auth and clients:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClientBody"}}}},"responses":{"200":{"description":"Updated client record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Client"}}}},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Client is disabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Clients"],"operationId":"deleteClient","summary":"Disable client","description":"Soft-disable a client by setting disabled_date and disabled_by. The record is retained for audit purposes. Requires session auth and clients:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"Client disabled","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Client is disabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/enable":{"post":{"tags":["Clients"],"operationId":"enableClient","summary":"Re-enable a soft-disabled client","description":"Clears `disabled_date` and `disabled_by` so the client becomes active again. Requires clients:WRITE.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"Client enabled","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Client is already active","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/features":{"get":{"tags":["Clients"],"operationId":"listClientFeatures","summary":"List client feature entitlements","description":"Return the feature names a client is currently entitled to (layer-1 entitlement, Maison-admin/business-plan tier). Includes omnichannel entitlements such as `channels` (the master switch for the Channels admin surface + inbound webhook auto-replies). Used by the Business Console Channels tab to render the master toggle. Requires global clients:READ (Maison-admin only).","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"Entitled feature list","content":{"application/json":{"schema":{"type":"object","required":["features"],"properties":{"features":{"type":"array","items":{"type":"string"},"description":"Feature names the client is entitled to"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Clients"],"operationId":"grantClientFeature","summary":"Grant a feature entitlement to a client","description":"Grants a feature entitlement to a client (Maison-admin/sales business-plan operation). Idempotent: re-granting a previously revoked feature restores it. Granting `channels` unlocks the omnichannel Channels admin surface and enables auto-replies for inbound messages (Instagram/Messenger/WhatsApp). Requires global clients:WRITE (Maison-admin only).","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["feature"],"properties":{"feature":{"type":"string","minLength":1,"maxLength":200,"description":"Feature name to grant (must exist in the features catalog)","example":"channels"}}}}}},"responses":{"201":{"description":"Feature granted","content":{"application/json":{"schema":{"type":"object","required":["feature"],"properties":{"feature":{"type":"string","description":"Granted feature name"}}}}}},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Feature not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/features/{feature}":{"delete":{"tags":["Clients"],"operationId":"revokeClientFeature","summary":"Revoke a feature entitlement from a client","description":"Revokes a feature entitlement from a client. No-op if the client is not entitled to the feature. Revoking `channels` stops inbound webhook auto-replies for the client; existing channel connections are preserved. Requires global clients:WRITE (Maison-admin only).","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"feature","in":"path","required":true,"schema":{"type":"string"},"description":"Feature name to revoke","example":"channels"}],"responses":{"200":{"description":"Feature revoked","content":{"application/json":{"schema":{"type":"object","required":["feature"],"properties":{"feature":{"type":"string","description":"Revoked feature name"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Feature not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/pipelinetasks":{"get":{"tags":["Clients"],"operationId":"listClientPipelineTasks","summary":"List running pipeline tasks for a client","description":"Returns all pipeline tasks currently in RUNNING state for the given client. Use to check whether a scrape or other task is already in progress before triggering a duplicate. Requires MaisonAdmin (ALL EXECUTE) — not accessible to hotel-level client admins.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"List of currently running pipeline tasks","content":{"application/json":{"schema":{"type":"object","required":["tasks","count"],"properties":{"tasks":{"type":"array","items":{"type":"object","required":["taskId","taskType","sourceKind","source","sessionId","startedAt","runningSeconds"],"properties":{"taskId":{"type":"string","description":"Pipeline task identifier"},"taskType":{"type":"string","description":"Pipeline task type (e.g. scrape-website, deduplicate-kb)"},"sourceKind":{"type":"string","enum":["website","document","knowledge","tests","analytics","unknown"],"description":"Semantic category of the data source the task operates on, derived from taskType: scrape-website/sync-website/discover-booking-links → website; scrape-document/ingest-source → document; deduplicate-kb/check-consistency → knowledge; run-prompt-tests → tests; run-ai-visibility → analytics; else → unknown."},"source":{"type":"string","nullable":true,"description":"The URL the task is operating on, or null when not applicable (e.g. for knowledge or document tasks)"},"sessionId":{"type":"string","nullable":true,"description":"Scrape session UUID (null when absent from command)"},"startedAt":{"type":"string","format":"date-time","description":"ISO 8601 timestamp when the task started (falls back to createdAt)"},"runningSeconds":{"type":"integer","description":"Seconds elapsed since the task started"}}}},"count":{"type":"integer","description":"Number of running tasks for this client"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/pipelinetasks/{taskId}":{"delete":{"tags":["Clients"],"operationId":"stopClientPipelineTask","summary":"Stop a running pipeline task for a client","description":"Stops a running pipeline task for the given client. The task must belong to the given client — tasks belonging to other clients are returned as not found (opaque 404). Tasks that have already stopped also return 404. Requires MaisonAdmin (ALL EXECUTE) — not accessible to hotel-level client admins. When a scrape task is stopped, its associated session record is marked as canceled; the `sessionMarked` response field indicates whether this update occurred.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"taskId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"},"description":"Pipeline task identifier (32 lowercase hexadecimal characters)"}],"responses":{"200":{"description":"Task stopped successfully","content":{"application/json":{"schema":{"type":"object","required":["stopped","taskId","sessionMarked"],"properties":{"stopped":{"type":"boolean","description":"Always true on success"},"taskId":{"type":"string","description":"The task identifier that was stopped"},"sessionMarked":{"type":"boolean","description":"true when the scrape session associated with this task was marked as canceled. false when the task had no associated session (e.g. non-scrape tasks), the session was already in a terminal status, or the status update could not be applied (best-effort)."}}}}}},"400":{"description":"Invalid client id or task id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Pipeline task not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/channels":{"get":{"tags":["Clients"],"operationId":"listClientChannels","summary":"List client channel connections","description":"Returns the client's active messaging channel connections (never includes access tokens) plus an `entitled` boolean indicating whether the client has the 'channels' feature. Requires session or API-key auth with update-client READ on the client.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"Channel list and entitlement status","content":{"application/json":{"schema":{"type":"object","required":["entitled","channels"],"properties":{"entitled":{"type":"boolean","description":"Whether the client is entitled to the Channels feature (client_feature_link row for 'channels' exists and is active)"},"channels":{"type":"array","items":{"type":"object","required":["id","channel","channelAccountId","status","autoReplyEnabled","createdDate"],"properties":{"id":{"type":"string","format":"uuid"},"channel":{"type":"string","enum":["INSTAGRAM","MESSENGER","WHATSAPP"],"description":"Channel type"},"channelAccountId":{"type":"string","description":"External account identifier (IG Business Account ID, Messenger Page ID, WhatsApp Phone Number ID)"},"channelUsername":{"type":"string","nullable":true,"description":"Human-readable account name (username, Page name) — null when not available"},"status":{"type":"string","description":"Connection health status (CONNECTED, ACTION_NEEDED, ERROR)"},"autoReplyEnabled":{"type":"boolean","description":"Whether the AI auto-reply is enabled for this channel"},"tokenExpiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Access token expiry (ISO 8601). Null for non-expiring tokens (e.g. Messenger page tokens)"},"createdDate":{"type":"string","format":"date-time","description":"When this channel connection was first established"}}}}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to list channel connections","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/channels/{channelId}":{"delete":{"tags":["Clients"],"operationId":"disconnectChannel","summary":"Disconnect a channel","description":"Soft-deletes the channel connection row (sets deleted_date). Does not revoke the token from Meta. Requires update-client WRITE on the client.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"channelId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Channel connection UUID"}],"responses":{"204":{"description":"Channel disconnected"},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Channel connection not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to disconnect channel","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"patch":{"tags":["Clients"],"operationId":"toggleChannelAutoReply","summary":"Toggle channel auto-reply","description":"Enable or disable AI auto-reply for a channel connection. Requires update-client WRITE on the client.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"channelId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Channel connection UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["autoReplyEnabled"],"properties":{"autoReplyEnabled":{"type":"boolean","description":"New auto-reply state"}}}}}},"responses":{"200":{"description":"Updated auto-reply state","content":{"application/json":{"schema":{"type":"object","required":["autoReplyEnabled"],"properties":{"autoReplyEnabled":{"type":"boolean"}}}}}},"400":{"description":"Invalid id or body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Channel connection not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to toggle auto-reply","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/channels/instructions":{"get":{"tags":["Clients"],"operationId":"listChannelInstructions","summary":"List all channel instructions","description":"Returns operator style instructions for all channel types keyed by channel TYPE (WEB, GMAIL, OUTLOOK, INSTAGRAM, MESSENGER, WHATSAPP, SMS uppercase). Requires update-client READ on the client.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"Instructions map keyed by channel type","content":{"application/json":{"schema":{"type":"object","required":["instructions"],"properties":{"instructions":{"type":"object","description":"Map of channel type (WEB, GMAIL, OUTLOOK, INSTAGRAM, MESSENGER, WHATSAPP, SMS) to array of instruction notes","additionalProperties":{"type":"array","items":{"type":"object","required":["id","title","text"],"properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"text":{"type":"string"}}}}}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to list channel instructions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/channels/{channelType}/instructions":{"post":{"tags":["Clients"],"operationId":"createChannelInstruction","summary":"Create a channel instruction","description":"Appends a titled instruction note to the ordered list for the given channel type. Channel type is case-insensitive in the URL (WEB, GMAIL, OUTLOOK, INSTAGRAM, MESSENGER, WHATSAPP, SMS). Requires update-client WRITE on the client.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"channelType","in":"path","required":true,"schema":{"type":"string","enum":["WEB","GMAIL","OUTLOOK","INSTAGRAM","MESSENGER","WHATSAPP","SMS"]},"description":"Channel type (case-insensitive in URL)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","text"],"properties":{"title":{"type":"string","maxLength":100,"description":"Instruction title","example":"Tone for Instagram"},"text":{"type":"string","maxLength":1000,"description":"Instruction body text","example":"Always respond in a warm, concise style. Keep replies under 3 sentences."}}},"example":{"title":"Tone for Instagram","text":"Always respond in a warm, concise style. Keep replies under 3 sentences."}}}},"responses":{"201":{"description":"Created instruction note","content":{"application/json":{"schema":{"type":"object","required":["id","title","text"],"properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"text":{"type":"string"}}}}}},"400":{"description":"Invalid client id, channel type, or body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to create channel instruction","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{id}/channels/{channelType}/instructions/{instructionId}":{"put":{"tags":["Clients"],"operationId":"updateChannelInstruction","summary":"Update a channel instruction","description":"Replaces the title and text of an existing instruction note. Requires update-client WRITE on the client.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"channelType","in":"path","required":true,"schema":{"type":"string","enum":["WEB","GMAIL","OUTLOOK","INSTAGRAM","MESSENGER","WHATSAPP","SMS"]},"description":"Channel type"},{"name":"instructionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Instruction note UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","text"],"properties":{"title":{"type":"string","maxLength":100,"description":"New title","example":"Tone for Instagram"},"text":{"type":"string","maxLength":1000,"description":"New body text","example":"Always respond in a warm, concise style. Keep replies under 3 sentences."}}},"example":{"title":"Tone for Instagram","text":"Always respond in a warm, concise style. Keep replies under 3 sentences."}}}},"responses":{"200":{"description":"Updated instruction note","content":{"application/json":{"schema":{"type":"object","required":["id","title","text"],"properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"text":{"type":"string"}}}}}},"400":{"description":"Invalid client id, channel type, instruction id, or body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Instruction not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to update channel instruction","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Clients"],"operationId":"deleteChannelInstruction","summary":"Delete a channel instruction","description":"Removes a titled instruction note from the channel's ordered list. Requires update-client WRITE on the client.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"channelType","in":"path","required":true,"schema":{"type":"string","enum":["WEB","GMAIL","OUTLOOK","INSTAGRAM","MESSENGER","WHATSAPP","SMS"]},"description":"Channel type"},{"name":"instructionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Instruction note UUID"}],"responses":{"204":{"description":"Instruction deleted"},"400":{"description":"Invalid client id, channel type, or instruction id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to delete channel instruction","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/instagram/connect":{"get":{"tags":["Clients"],"operationId":"instagramConnectInitiate","summary":"Start Instagram Business Login OAuth flow","description":"Initiates the Instagram Business Login flow for a client. Requires session or API-key auth with update-client WRITE on the client. Redirects (302) to the Instagram authorize URL with an HMAC-signed state binding clientId + userId. Optionally accepts a `returnTo` query param (allowlisted to /console/ and /qa/ prefixes) — if provided, the callback will redirect to that URL instead of the default Channels tab.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID to connect an Instagram account for"},{"name":"returnTo","in":"query","required":false,"schema":{"type":"string"},"description":"URL to redirect to after OAuth completion. Must start with {siteHost}/console/ or {siteHost}/qa/. The result param (instagram=connected|denied|error) is appended. Rejected with 400 if not allowlisted."}],"responses":{"302":{"description":"Redirect to Instagram authorize URL"},"400":{"description":"Invalid clientId or returnTo not allowlisted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Instagram connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/instagram/connect/callback":{"get":{"tags":["Clients"],"operationId":"instagramConnectCallback","summary":"Instagram Business Login OAuth callback","description":"Meta redirects here after the user completes or denies the Instagram authorization flow. Verifies the HMAC-signed state, exchanges the code for a long-lived token, upserts the channel connection, and redirects back to the Channels tab (or the returnTo URL from state if present and allowlisted).","parameters":[{"name":"code","in":"query","schema":{"type":"string"},"description":"Authorization code from Meta"},{"name":"state","in":"query","schema":{"type":"string"},"description":"HMAC-signed state from the initiate step"},{"name":"error","in":"query","schema":{"type":"string"},"description":"Error code when the user denied the flow"}],"responses":{"302":{"description":"Redirect to Channels tab or returnTo URL"},"400":{"description":"Missing code/state or invalid state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Instagram connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/messenger/connect":{"get":{"tags":["Clients"],"operationId":"messengerConnectInitiate","summary":"Start Messenger Facebook Login for Business OAuth flow","description":"Initiates the Messenger connect flow (Facebook Login for Business) for a client. Requires session or API-key auth with update-client WRITE. Redirects (302) to the Facebook authorize URL with an HMAC-signed state. Optionally accepts a `returnTo` query param (allowlisted to /console/ and /qa/ prefixes).","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID to connect a Messenger Page for"},{"name":"returnTo","in":"query","required":false,"schema":{"type":"string"},"description":"URL to redirect to after OAuth completion. Must start with {siteHost}/console/ or {siteHost}/qa/. The result param (messenger=connected|denied|error|nopages|multiplepages) is appended. Rejected with 400 if not allowlisted."}],"responses":{"302":{"description":"Redirect to Facebook authorize URL"},"400":{"description":"Invalid clientId or returnTo not allowlisted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Messenger connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/messenger/connect/callback":{"get":{"tags":["Clients"],"operationId":"messengerConnectCallback","summary":"Messenger OAuth callback","description":"Facebook redirects here after the user completes or denies the Messenger authorization flow. Verifies state, exchanges the code for a user token, retrieves managed Pages, subscribes the single Page to the app, upserts the channel connection, and redirects back to Channels tab (or returnTo if in state and allowlisted). Returns nopages or multiplepages result when the user's token covers 0 or >1 Pages.","parameters":[{"name":"code","in":"query","schema":{"type":"string"},"description":"Authorization code from Facebook"},{"name":"state","in":"query","schema":{"type":"string"},"description":"HMAC-signed state from the initiate step"},{"name":"error","in":"query","schema":{"type":"string"},"description":"Error code when the user denied the flow"}],"responses":{"302":{"description":"Redirect to Channels tab or returnTo URL"},"400":{"description":"Missing code/state or invalid state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Messenger connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/whatsapp/connect":{"get":{"tags":["Clients"],"operationId":"whatsappConnectConfig","summary":"Get WhatsApp Embedded Signup config","description":"Returns the public Embedded Signup config { appId, configId, state } for the Facebook JS SDK popup flow. Unlike Instagram/Messenger (redirect OAuth), WhatsApp connects client-side via FB.login with a config_id; the HMAC-signed state binds {clientId, userId} for CSRF verification at the POST callback. Requires session or API-key auth with update-client WRITE.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID to connect a WhatsApp Business number for"}],"responses":{"200":{"description":"Embedded Signup config","content":{"application/json":{"schema":{"type":"object","properties":{"appId":{"type":"string"},"configId":{"type":"string"},"state":{"type":"string"}}}}}},"400":{"description":"Invalid clientId","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"WhatsApp connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/whatsapp/connect/callback":{"post":{"tags":["Clients"],"operationId":"whatsappConnectCallback","summary":"Complete WhatsApp Embedded Signup","description":"Submits the Embedded Signup result. Verifies the HMAC-signed state (clientId + userId binding), exchanges the code for a business token, verifies WABA ownership, registers the phone number, subscribes the WABA to the app, and upserts the channel connection. phoneNumberId is omitted on the Coexistence path (FINISH_WHATSAPP_BUSINESS_APP_ONBOARDING carries only the waba_id) — the number is then resolved from the WABA and registration is skipped. Requires session or API-key auth with update-client WRITE.","security":[{"sessionAuth":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["clientId","code","wabaId","state"],"properties":{"clientId":{"type":"string","format":"uuid"},"code":{"type":"string"},"wabaId":{"type":"string"},"phoneNumberId":{"type":"string"},"state":{"type":"string"}}}}}},"responses":{"200":{"description":"WhatsApp Business connected"},"400":{"description":"Invalid body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Invalid or mismatched state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"502":{"description":"Meta API error during code exchange or WABA setup","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"WhatsApp connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/outlook/connect":{"get":{"tags":["Clients"],"operationId":"outlookConnectInitiate","summary":"Start Outlook (Microsoft Graph) OAuth flow","description":"Initiates the delegated Microsoft Graph OAuth flow for a client. Requires session or API-key auth with update-client WRITE on the client. Redirects (302) to the Microsoft authorize URL with an HMAC-signed state binding clientId + userId (signed with the Microsoft client secret). Optionally accepts a `returnTo` query param (allowlisted to /console/ and /qa/ prefixes) — if provided, the callback will redirect to that URL instead of the default Channels tab.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID to connect an Outlook mailbox for"},{"name":"returnTo","in":"query","required":false,"schema":{"type":"string"},"description":"URL to redirect to after OAuth completion. Must start with {siteHost}/console/ or {siteHost}/qa/. The result param (outlook=connected|denied|error) is appended. Rejected with 400 if not allowlisted."}],"responses":{"302":{"description":"Redirect to Microsoft authorize URL"},"400":{"description":"Invalid clientId or returnTo not allowlisted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Outlook connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/outlook/connect/callback":{"get":{"tags":["Clients"],"operationId":"outlookConnectCallback","summary":"Outlook (Microsoft Graph) OAuth callback","description":"Microsoft redirects here after the user completes or denies the Outlook authorization flow. Verifies the HMAC-signed state, exchanges the code for access + refresh tokens, reads the mailbox address from Graph /me, upserts the OUTLOOK channel connection, and redirects back to the Channels tab (or the returnTo URL from state if present and allowlisted).","parameters":[{"name":"code","in":"query","schema":{"type":"string"},"description":"Authorization code from Microsoft"},{"name":"state","in":"query","schema":{"type":"string"},"description":"HMAC-signed state from the initiate step"},{"name":"error","in":"query","schema":{"type":"string"},"description":"Error code when the user denied the flow"}],"responses":{"302":{"description":"Redirect to Channels tab or returnTo URL"},"400":{"description":"Missing code/state or invalid state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Outlook connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/gmail/connect":{"get":{"tags":["Clients"],"operationId":"gmailConnectInitiate","summary":"Start Gmail (Google) OAuth flow","description":"Initiates the Gmail send-first OAuth flow for a client. Requires session or API-key auth with update-client WRITE on the client. Redirects (302) to the Google authorize URL (access_type=offline, prompt=consent so a refresh token is returned) with an HMAC-signed state binding clientId + userId (signed with the Google client secret). Optionally accepts a `returnTo` query param (allowlisted to /console/ and /qa/ prefixes) — if provided, the callback will redirect to that URL instead of the default Channels tab.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID to connect a Gmail mailbox for"},{"name":"returnTo","in":"query","required":false,"schema":{"type":"string"},"description":"URL to redirect to after OAuth completion. Must start with {siteHost}/console/ or {siteHost}/qa/. The result param (gmail=connected|denied|error) is appended. Rejected with 400 if not allowlisted."}],"responses":{"302":{"description":"Redirect to Google authorize URL"},"400":{"description":"Invalid clientId or returnTo not allowlisted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Gmail connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/gmail/connect/callback":{"get":{"tags":["Clients"],"operationId":"gmailConnectCallback","summary":"Gmail (Google) OAuth callback","description":"Google redirects here after the user completes or denies the Gmail authorization flow. Verifies the HMAC-signed state, exchanges the code for access + refresh tokens, reads the mailbox address from the id_token email claim, upserts the GMAIL channel connection, and redirects back to the Channels tab (or the returnTo URL from state if present and allowlisted).","parameters":[{"name":"code","in":"query","schema":{"type":"string"},"description":"Authorization code from Google"},{"name":"state","in":"query","schema":{"type":"string"},"description":"HMAC-signed state from the initiate step"},{"name":"error","in":"query","schema":{"type":"string"},"description":"Error code when the user denied the flow"}],"responses":{"302":{"description":"Redirect to Channels tab or returnTo URL"},"400":{"description":"Missing code/state or invalid state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Gmail connect is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users":{"get":{"tags":["Users"],"operationId":"listUsers","summary":"List users","description":"Return a paginated, searchable, sortable list of users. Requires session auth and users:READ permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of users to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against name and email"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","disabled","invited","expired"]},"description":"Filter by computed user status"},{"name":"order_by","in":"query","schema":{"type":"string","enum":["email","first_name","last_name","created_date","last_login_date","status"],"default":"created_date"},"description":"Column to sort by"},{"name":"sort","in":"query","schema":{"type":"string","enum":["ASC","DESC"],"default":"DESC"},"description":"Sort direction"}],"responses":{"200":{"description":"Paginated list of users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserListResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/invite":{"post":{"tags":["Users"],"operationId":"inviteUser","summary":"Invite a new user","description":"Create a user record and send an invitation email. The user must accept the invite to activate their account. Requires session auth and users:WRITE permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserBody"}}}},"responses":{"201":{"description":"User invited — invitation email sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"A user with this email already exists","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process invitation","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/reinvite":{"post":{"tags":["Users"],"operationId":"reinviteUser","summary":"Reinvite a user","description":"Resend an invitation to a user whose status is 'invited' or 'expired'. Resets the invite expiry date. Returns 409 if the user has already accepted their invite or is disabled. Requires session auth and users:WRITE permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinviteUserBody"}}}},"responses":{"200":{"description":"Invite resent — updated expiry date returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserResponse"}}}},"400":{"description":"Invalid user id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"User has already accepted their invite or is disabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process reinvite","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/forcereset":{"post":{"tags":["Users"],"operationId":"forceResetUser","summary":"Force password reset for a user","description":"Sets force_reset_password = true and sends a password reset email via Firebase. The user must be active (accepted invite, not disabled). Returns 409 if the user has not accepted their invite or is disabled. If email sending fails the flag is still set and 200 is returned. Requires session auth and users:WRITE permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"responses":{"200":{"description":"Password reset email sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForceResetResponse"}}}},"400":{"description":"Invalid user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"User has not accepted their invite yet or is disabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/setpassword":{"post":{"tags":["Users"],"operationId":"setUserPassword","summary":"Directly set a user's password (admin only)","description":"Directly sets the user's Firebase password to the supplied value. Requires session auth and users:WRITE permission. NOTE: This endpoint is intentionally REST-only and is NOT exposed via A2A or MCP. Direct admin password-set is a sensitive privileged operation — force-reset (POST /api/users/{id}/forcereset) is the agent-safe path that sends a password reset email instead.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["password"],"properties":{"password":{"type":"string","minLength":8}}}}}},"responses":{"200":{"description":"Password updated","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid user id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/activity":{"get":{"tags":["Users"],"operationId":"getUserActivity","summary":"Get user activity timeline","description":"Return a paginated activity timeline for a user. Events are assembled from role assignments, group membership changes, API key operations, invitations, and login history. Ordered by event_date DESC. Requires session auth and users:READ permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"description":"Maximum number of events to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"}],"responses":{"200":{"description":"Paginated activity timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserActivityResponse"}}}},"400":{"description":"Invalid user id or query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}":{"get":{"tags":["Users"],"operationId":"getUser","summary":"Get user by ID","description":"Fetch a single user record by UUID. Requires session auth and users:READ permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"responses":{"200":{"description":"User record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserListItem"}}}},"400":{"description":"Invalid user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Users"],"operationId":"updateUser","summary":"Update user","description":"Partially update a user record. All body fields are optional. Set `enable: false` to disable or `enable: true` to re-enable. Requires session auth and users:WRITE permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserBody"}}}},"responses":{"200":{"description":"Updated user record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserListItem"}}}},"400":{"description":"Invalid user id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"User is already in the requested state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Users"],"operationId":"disableUser","summary":"Disable user","description":"Soft-disable a user by setting disabled_date and disabled_by. The record is retained for audit purposes. Requires session auth and users:WRITE permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"responses":{"200":{"description":"User disabled","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"User is already disabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/roles":{"get":{"tags":["Roles"],"operationId":"listRoles","summary":"List roles","description":"Return a paginated, searchable, sortable list of roles. Requires session auth and roles:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of roles to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against role name and description"},{"name":"order_by","in":"query","schema":{"type":"string","enum":["name","created_date","policy_count","user_count"],"default":"created_date"},"description":"Column to sort by"},{"name":"sort","in":"query","schema":{"type":"string","enum":["ASC","DESC"],"default":"DESC"},"description":"Sort direction"}],"responses":{"200":{"description":"Paginated list of roles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Roles"],"operationId":"createRole","summary":"Create role","description":"Create a new role. Requires session auth and roles:WRITE permission.","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleBody"}}}},"responses":{"201":{"description":"Role created","content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/roles/{id}":{"get":{"tags":["Roles"],"operationId":"getRole","summary":"Get role by ID","description":"Fetch a single role with its policies. Requires session auth and roles:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"}],"responses":{"200":{"description":"Role detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Role not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Roles"],"operationId":"updateRole","summary":"Update role","description":"Partially update a role. All body fields are optional; at least one must be provided. Requires session auth and roles:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleBody"}}}},"responses":{"200":{"description":"Updated role detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Role not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Roles"],"operationId":"disableRole","summary":"Disable role","description":"Soft-disable a role by setting disabled_date and disabled_by. The record is retained for audit purposes. Requires session auth and roles:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"}],"responses":{"200":{"description":"Role disabled","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Role not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/roles/{id}/policies":{"post":{"tags":["Roles"],"operationId":"addPolicy","summary":"Add policy to role","description":"Attach a new policy to a role. Requires session auth and roles:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddPolicyBody"}}}},"responses":{"201":{"description":"Policy added","content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Role not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/roles/{id}/policies/{policyId}":{"delete":{"tags":["Roles"],"operationId":"removePolicy","summary":"Remove policy from role","description":"Remove a policy from a role. Requires session auth and roles:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"},{"name":"policyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Policy UUID"}],"responses":{"200":{"description":"Policy removed","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Role or policy not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/roles/{id}/users/{userId}":{"delete":{"tags":["Roles"],"operationId":"removeRoleUser","summary":"Remove a user's direct role link","description":"Soft-deletes every active direct user_role_link for the given (role, user). Does NOT touch group-inherited access. Idempotent — returns { removed } count.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"responses":{"200":{"description":"Remove operation completed","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"integer"}}}}}},"400":{"description":"Invalid role or user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/roles/{id}/users":{"post":{"tags":["Roles"],"operationId":"addRoleUser","summary":"Attach a user to a role","description":"Create a direct user_role_link between this role and the given user. Optional client_id scopes the assignment to a single client; omit for a global link. Reviving a soft-deleted link is idempotent.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["user_id"],"properties":{"user_id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid","nullable":true,"description":"Optional client scope; null/omitted creates a global link."}}}}}},"responses":{"201":{"description":"User attached to role","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"get":{"tags":["Roles"],"operationId":"listRoleUsers","summary":"List users assigned to a role","description":"Return a paginated list of users assigned to this role. Requires session auth and roles:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of users to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"}],"responses":{"200":{"description":"Paginated list of users assigned to this role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleUsersResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/roles/{id}/groups":{"post":{"tags":["Roles"],"operationId":"addRoleGroup","summary":"Attach a user group to a role","description":"Create a user_group_role_link between this role and the given user group. Optional client_id scopes the assignment to a single client. Reviving a soft-deleted link is idempotent.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["user_group_id"],"properties":{"user_group_id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid","nullable":true,"description":"Optional client scope; null/omitted creates a global link."}}}}}},"responses":{"201":{"description":"Group attached to role","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"get":{"tags":["Roles"],"operationId":"listRoleGroups","summary":"List groups assigned to a role","description":"Return a paginated list of groups assigned to this role. Requires session auth and roles:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Role UUID"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of groups to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"}],"responses":{"200":{"description":"Paginated list of groups assigned to this role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleGroupsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/features":{"get":{"tags":["Features"],"operationId":"listFeatures","summary":"List features","description":"Return a paginated, searchable list of features. Requires session auth and features:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of features to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against feature name and description"}],"responses":{"200":{"description":"Paginated list of features","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Features"],"operationId":"createFeature","summary":"Create feature","description":"Create a new feature. Requires session auth and features:WRITE permission.","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFeatureBody"}}}},"responses":{"201":{"description":"Feature created","content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/features/{id}":{"put":{"tags":["Features"],"operationId":"updateFeature","summary":"Update feature","description":"Partially update a feature. All body fields are optional. Requires session auth and features:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Feature ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeatureBody"}}}},"responses":{"200":{"description":"Updated feature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureItem"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Feature not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Features"],"operationId":"deprecateFeature","summary":"Deprecate feature","description":"Mark a feature as deprecated. The record is retained. Requires session auth and features:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Feature ID"}],"responses":{"200":{"description":"Feature deprecated","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Feature not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/usergroups":{"get":{"tags":["User Groups"],"operationId":"listUserGroups","summary":"List user groups","description":"Return a paginated, searchable, sortable list of user groups. Requires session auth and user-groups:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of groups to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against group name and description"},{"name":"order_by","in":"query","schema":{"type":"string","enum":["name","member_count","created_date"],"default":"created_date"},"description":"Column to sort by"},{"name":"sort","in":"query","schema":{"type":"string","enum":["ASC","DESC"],"default":"DESC"},"description":"Sort direction"}],"responses":{"200":{"description":"Paginated list of user groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["User Groups"],"operationId":"createUserGroup","summary":"Create user group","description":"Create a new user group. Requires session auth and user-groups:WRITE permission.","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserGroupBody"}}}},"responses":{"201":{"description":"User group created","content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/usergroups/{id}":{"get":{"tags":["User Groups"],"operationId":"getUserGroup","summary":"Get user group detail","description":"Fetch a single user group with its members and roles. Requires session auth and user-groups:READ permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User group UUID"}],"responses":{"200":{"description":"User group detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroupDetail"}}}},"400":{"description":"Invalid group id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["User Groups"],"operationId":"updateUserGroup","summary":"Update user group","description":"Partially update a user group. All body fields are optional. Requires session auth and user-groups:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User group UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserGroupBody"}}}},"responses":{"200":{"description":"Updated user group detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroupDetail"}}}},"400":{"description":"Invalid group id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["User Groups"],"operationId":"deleteUserGroup","summary":"Delete user group","description":"Soft-delete a user group by setting deleted_date. The record is retained for audit purposes. Requires session auth and user-groups:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User group UUID"}],"responses":{"200":{"description":"Group deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid group id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/usergroups/{id}/members":{"put":{"tags":["User Groups"],"operationId":"updateGroupMembers","summary":"Add/remove group members","description":"Add and/or remove members from a user group in a single request. Requires session auth and user-groups:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User group UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupMembersBody"}}}},"responses":{"200":{"description":"Members updated — counts of added and removed records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupMembersResponse"}}}},"400":{"description":"Invalid group id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/usergroups/{id}/roles":{"put":{"tags":["User Groups"],"operationId":"updateGroupRoles","summary":"Assign/remove group roles","description":"Assign and/or remove roles from a user group in a single request. Requires session auth and user-groups:WRITE permission.","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User group UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupRolesBody"}}}},"responses":{"200":{"description":"Roles updated — counts of added and removed records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupRolesResponse"}}}},"400":{"description":"Invalid group id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/users":{"get":{"tags":["Clients"],"operationId":"listClientUsers","summary":"List users with access to a client","description":"Returns every user who has a non-deleted user_role_link OR is a member of a user_group with a non-deleted user_group_role_link scoped to this client. Aggregated per user with role + permission summary.","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"responses":{"200":{"description":"List of users with access","content":{"application/json":{"schema":{"type":"object","required":["items","total","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Clients"],"operationId":"addClientUser","summary":"Add a user to a client (invite new or attach existing)","description":"Auto-detects by email. If the user exists, inserts a user_role_link for (user, client, role). If not, provisions a Firebase user + sends an invite with the role attached. role_id must be assignable for this client (not Maison-only, not disabled).","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","role_id"],"properties":{"email":{"type":"string","format":"email"},"role_id":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"last_name":{"type":"string"}}}}}},"responses":{"200":{"description":"Existing user attached","content":{"application/json":{"schema":{"type":"object","required":["kind","user_id"],"properties":{"kind":{"type":"string","enum":["attached"]},"user_id":{"type":"string","format":"uuid"}}}}}},"201":{"description":"New user invited","content":{"application/json":{"schema":{"type":"object","required":["kind","user_id"],"properties":{"kind":{"type":"string","enum":["invited"]},"user_id":{"type":"string","format":"uuid"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Role is not assignable for this client","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Email already registered in Firebase","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/users/{userId}":{"delete":{"tags":["Clients"],"operationId":"removeClientUser","summary":"Remove all direct role-links for (user, client)","description":"Soft-deletes every active user_role_link for this user-client pair. Does NOT touch user_group memberships. Idempotent.","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role links removed","content":{"application/json":{"schema":{"type":"object","required":["removed"],"properties":{"removed":{"type":"integer"}}}}}},"400":{"description":"Invalid client or user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/usergroups":{"get":{"tags":["Clients"],"operationId":"listClientUserGroups","summary":"List user-groups with role links on this client","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of user-groups with role links","content":{"application/json":{"schema":{"type":"object","required":["items","total","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Clients"],"operationId":"addClientGroup","summary":"Attach an existing user group to this client with a role","description":"Adds a role link for (group, client). Group must already exist (this endpoint does not create groups). Role must be assignable for this client.","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["group_id","role_id"],"properties":{"group_id":{"type":"string","format":"uuid"},"role_id":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Group attached","content":{"application/json":{"schema":{"type":"object","required":["kind","group_id"],"properties":{"kind":{"type":"string","enum":["attached"]},"group_id":{"type":"string","format":"uuid"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Role is not assignable for this client","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/usergroups/{groupId}":{"delete":{"tags":["Clients"],"operationId":"removeClientUserGroup","summary":"Remove all role-links for (group, client)","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role links removed","content":{"application/json":{"schema":{"type":"object","required":["removed"],"properties":{"removed":{"type":"integer"}}}}}},"400":{"description":"Invalid client or group id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/roles":{"get":{"tags":["Clients"],"operationId":"listClientAssignableRoles","summary":"List roles that can be assigned to users/groups for this client","description":"Excludes disabled roles and roles marked visibility_maison_only=true (Maison-admin-only). Returns both global roles and client-scoped roles belonging to this client.","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Assignable roles","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/regions":{"get":{"tags":["Settings"],"operationId":"listRegions","summary":"List regions","description":"Return a paginated, searchable list of regions for a client. Requires session auth and settings:READ permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of regions to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against region name"}],"responses":{"200":{"description":"Paginated list of regions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegionListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Settings"],"operationId":"createRegion","summary":"Create region","description":"Create a new region for a client. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRegionBody"}}}},"responses":{"201":{"description":"Region created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/regions/{id}":{"put":{"tags":["Settings"],"operationId":"updateRegion","summary":"Update region","description":"Partially update a region. All body fields are optional. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Region UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRegionBody"}}}},"responses":{"200":{"description":"Updated region","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegionListItem"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Region not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Settings"],"operationId":"deleteRegion","summary":"Delete region","description":"Soft-delete a region by setting deleted_date. The record is retained for audit purposes. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Region UUID"}],"responses":{"200":{"description":"Region deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Region not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/departments":{"get":{"tags":["Settings"],"operationId":"listDepartments","summary":"List departments","description":"Return a paginated, searchable list of departments for a client. Requires session auth and settings:READ permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of departments to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against department name"}],"responses":{"200":{"description":"Paginated list of departments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepartmentListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Settings"],"operationId":"createDepartment","summary":"Create department","description":"Create a new department for a client. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDepartmentBody"}}}},"responses":{"201":{"description":"Department created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/departments/{id}":{"put":{"tags":["Settings"],"operationId":"updateDepartment","summary":"Update department","description":"Partially update a department. All body fields are optional. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Department UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDepartmentBody"}}}},"responses":{"200":{"description":"Updated department","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepartmentListItem"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Department not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Settings"],"operationId":"deleteDepartment","summary":"Delete department","description":"Soft-delete a department by setting deleted_date. The record is retained for audit purposes. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Department UUID"}],"responses":{"200":{"description":"Department deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Department not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/tags":{"get":{"tags":["Settings"],"operationId":"listTags","summary":"List tags","description":"Return a paginated, searchable list of tags for a client. Requires session auth and settings:READ permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of tags to return (1-100)"},{"name":"after","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor returned in the previous response as `nextCursor`"},{"name":"search","in":"query","schema":{"type":"string","maxLength":100},"description":"Case-insensitive search string matched against tag name"}],"responses":{"200":{"description":"Paginated list of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Settings"],"operationId":"createTag","summary":"Create tag","description":"Create a new tag for a client. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTagBody"}}}},"responses":{"201":{"description":"Tag created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/clients/{clientId}/tags/{id}":{"put":{"tags":["Settings"],"operationId":"updateTag","summary":"Update tag","description":"Partially update a tag. All body fields are optional. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Tag UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTagBody"}}}},"responses":{"200":{"description":"Updated tag","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListItem"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Tag not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Settings"],"operationId":"deleteTag","summary":"Delete tag","description":"Soft-delete a tag by setting deleted_date. The record is retained for audit purposes. Requires session auth and settings:WRITE permission.","security":[{"apiKey":[]},{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Tag UUID"}],"responses":{"200":{"description":"Tag deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Tag not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/auth/":{"post":{"tags":["Legacy"],"operationId":"legacyBcAuthLogin","summary":"DEPRECATED: Legacy login","description":"DEPRECATED: Accepts legacy Basic-in-body credentials and issues a session cookie. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"auth":{"type":"string"}}}}}},"responses":{"200":{"description":"Login successful"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Invalid credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/auth/logout":{"post":{"tags":["Legacy"],"operationId":"legacyBcAuthLogout","summary":"DEPRECATED: Legacy logout","description":"DEPRECATED: Revokes the session cookie. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","responses":{"200":{"description":"Logged out"},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client":{"post":{"tags":["Legacy"],"operationId":"legacyBcClientCreate","summary":"DEPRECATED: Create client","description":"DEPRECATED: Creates a new client with an associated website and hotel config, and deploys the demo preview site (best-effort; matches the legacy agent-server which deployed it on create). Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","website"],"properties":{"name":{"type":"string"},"demoClient":{"type":"boolean"},"website":{"type":"string","format":"uri"},"previewSiteConfiguration":{"type":"object"},"hotelConfig":{"type":"object"},"scrapeLanguage":{"type":"string"}}}}}},"responses":{"201":{"description":"Created — { client: { id } }"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"get":{"tags":["Legacy"],"operationId":"legacyBcClientGet","summary":"DEPRECATED: Get client","description":"DEPRECATED: Returns the client identified by x-client-id header. Consumer: legacy/business-console. The `websiteScrapeStatus` object includes an optional `message: string | null` field populated from `meta.abortMessage` when the session was aborted by an operator (meta.aborted === true); null otherwise.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Client record"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBcClientUpdate","summary":"DEPRECATED: Update client","description":"DEPRECATED: Updates the client identified by x-client-id header. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated client"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client/list":{"get":{"tags":["Legacy"],"operationId":"legacyBcClientList","summary":"DEPRECATED: List clients","description":"DEPRECATED: Returns all active clients as an array. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Array of clients"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client/summary":{"get":{"tags":["Legacy"],"operationId":"legacyBcClientSummary","summary":"DEPRECATED: Get client summary","description":"DEPRECATED: Returns minimal client summary. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Client summary"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/hotelconfiguration":{"get":{"tags":["Legacy"],"operationId":"legacyBcHotelConfigurationGet","summary":"Legacy: Get hotel configuration","description":"Legacy: Returns the hotel configuration object for the client. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hotel configuration object"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBcHotelConfiguration","summary":"Legacy: Update hotel configuration","description":"Legacy: Merges the provided fields into the hotel configuration for the client. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated hotel configuration"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Legacy"],"operationId":"legacyBcHotelConfigurationDelete","summary":"Legacy: Remove hotel configuration fields","description":"Legacy: Removes specified top-level fields from the hotel configuration for the client. Field names may be provided via x-configuration-fields header (comma-separated) or body.fields array. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"x-configuration-fields","in":"header","required":false,"schema":{"type":"string"},"description":"Comma-separated field names to remove (alternative to body.fields)"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated hotel configuration after field removal"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/website":{"post":{"tags":["Legacy"],"operationId":"legacyBcWebsiteCreate","summary":"Legacy: Add website knowledge source","description":"Legacy: Resolves or inserts a websites row, links it to the client, optionally promotes it as the primary website, and kicks off an initial scrape. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","format":"uri"},"updateClientWebsite":{"type":"boolean"},"syncSchedule":{"type":"string","enum":["NONE","DAILY","WEEKLY","BI_WEEKLY","MONTHLY"]},"language":{"type":"string"}}}}}},"responses":{"201":{"description":"Website source created and scrape queued"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Website already linked to client","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Knowledge source storage not provisioned","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBcWebsiteUpdate","summary":"Legacy: Update primary website sync schedule","description":"Legacy: Updates the syncSchedule for the primary website source of the client. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client/source/list":{"get":{"tags":["Legacy"],"operationId":"legacyBcClientSourceList","summary":"DEPRECATED: List client knowledge sources","description":"DEPRECATED: Returns knowledge source links for the client. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"includedeleted","in":"query","required":false,"schema":{"type":"boolean"},"description":"When true, includes soft-deleted source links. Default: false."}],"responses":{"200":{"description":"Array of source links"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/website/{id}/sync":{"put":{"tags":["Legacy"],"operationId":"legacyBcWebsiteSync","summary":"DEPRECATED: Trigger website sync","description":"DEPRECATED: Returns 202 Accepted; actual sync is pipeline-side. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Sync queued"},"400":{"description":"Invalid website id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/qa/counts":{"get":{"tags":["Legacy"],"operationId":"legacyQaCounts","summary":"DEPRECATED: QA pair counts","description":"DEPRECATED: Returns active/deleted/total counts for a client's QA namespace. Consumer: legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"qa-editor","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"QA pair counts","content":{"application/json":{"schema":{"type":"object","properties":{"active":{"type":"integer"},"deleted":{"type":"integer"},"total":{"type":"integer"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/qa/deduplicate":{"post":{"tags":["Legacy"],"operationId":"legacyBcQaDeduplicate","summary":"DEPRECATED: Deduplicate QA","description":"DEPRECATED: Enqueues a deduplicate-kb pipeline task. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"similarityThreshold":{"type":"number"},"batchSize":{"type":"integer"}}}}}},"responses":{"202":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"queued":{"type":"boolean"},"messageId":{"type":"string","nullable":true}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/qa/consistencycheck":{"post":{"tags":["Legacy"],"operationId":"legacyBcQaConsistencyCheck","summary":"DEPRECATED: QA consistency check","description":"DEPRECATED: Enqueues a check-consistency pipeline task. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"}}}}}},"responses":{"202":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"queued":{"type":"boolean"},"messageId":{"type":"string","nullable":true}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client/asset":{"post":{"tags":["Legacy"],"operationId":"legacyBcClientAsset","summary":"DEPRECATED: Upload client asset","description":"DEPRECATED: Uploads an image asset for the client. Named visual-branding uploads (assetType=icon|hero|heroDark) replace the corresponding branding asset; library uploads (no assetType) append to the client asset list. Returns the stored asset URL. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Raster image to upload. The type is validated from the file's magic bytes (PNG, JPEG, GIF, or WEBP only); SVG and other/spoofed types are rejected with 400. The stored extension is derived from the detected type, not the filename."},"assetType":{"type":"string","enum":["icon","hero","heroDark"],"description":"Visual-branding asset type. Omit for general library upload."},"description":{"type":"string","description":"Optional description (library uploads only)"},"published":{"type":"boolean","description":"Published flag (library uploads only)"}}}}}},"responses":{"200":{"description":"Asset uploaded","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"asset_url":{"type":"string","description":"URL of the stored asset"}}}}}},"400":{"description":"Invalid client id / Missing file / Unknown asset type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Asset storage not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Legacy"],"operationId":"legacyBcClientAssetDelete","summary":"DEPRECATED: Delete client asset","description":"DEPRECATED: Deletes a named visual-branding asset (?assetType=icon|hero|heroDark) or a general library asset (?assetType=<id>). Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"assetType","in":"query","required":true,"schema":{"type":"string"},"description":"Visual-branding type (icon|hero|heroDark) or library asset id"}],"responses":{"200":{"description":"Asset deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"description":"Invalid client id / Missing asset type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/translations":{"put":{"tags":["Legacy"],"operationId":"legacyBcTranslationsUpdate","summary":"DEPRECATED: Update translations","description":"DEPRECATED: Updates UI translations for the client; returns 204. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"204":{"description":"Accepted"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/analytics/chatlogs":{"post":{"tags":["Legacy"],"operationId":"legacyBcAnalyticsChatlogs","summary":"DEPRECATED: Trigger chat-logs analytics","description":"DEPRECATED: Queues a chat-log analytics report for the specified date range. The response returns immediately; report generation and email delivery happen in the background — failures are recorded on the analytics run status, not the HTTP response. Custom mode when recipients.to is supplied; scheduled mode otherwise. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string","description":"Client UUID (falls back to x-client-id header)"},"startDate":{"type":"string","format":"date-time","description":"Start of date range (ISO 8601). Defaults to 8 days ago."},"endDate":{"type":"string","format":"date-time","description":"End of date range (ISO 8601). Defaults to 24 hours ago."},"recipients":{"type":"object","description":"Custom recipients. When present triggers custom mode (no unsubscribe). to is required.","required":["to"],"properties":{"to":{"type":"array","items":{"type":"string","format":"email"}},"cc":{"type":"array","items":{"type":"string","format":"email"}},"bcc":{"type":"array","items":{"type":"string","format":"email"}}}}}}}}},"responses":{"202":{"description":"Accepted — report queued; delivered to the recipients by email when ready","content":{"application/json":{"schema":{"type":"object","properties":{"analyticsId":{"type":"string"},"queued":{"type":"boolean"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"422":{"description":"No chat logs found for the specified date range","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/logs/chat":{"get":{"tags":["Legacy"],"operationId":"legacyBcLogsChat","summary":"DEPRECATED: Download chat logs as XLSX","description":"DEPRECATED: Streams an XLSX download of raw chat-log messages for a client in the given date window. Returns 204 when no logs match. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"startDate","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"ISO 8601 window start"},{"name":"endDate","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"ISO 8601 window end"},{"name":"skipFresh","in":"query","required":false,"schema":{"type":"string"},"description":"true (default) omits first-visit sessions"},{"name":"skipAdmin","in":"query","required":false,"schema":{"type":"string"},"description":"true (default) omits admin sessions"},{"name":"skipTestSessions","in":"query","required":false,"schema":{"type":"string"},"description":"true (default) omits test sessions"}],"responses":{"200":{"description":"XLSX workbook download","headers":{"Content-Disposition":{"description":"attachment; filename=\"<slug>-chatlogs-<start>-<end>.xlsx\"","schema":{"type":"string"}}},"content":{"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"204":{"description":"No chat logs match the date range"},"400":{"description":"Invalid request (client id / date range)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Client not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/analytics/aivisibility":{"post":{"tags":["Legacy"],"operationId":"legacyBcAnalyticsAiVisibility","summary":"DEPRECATED: Trigger AI visibility analytics","description":"DEPRECATED: Enqueues a run-ai-visibility pipeline task. sessionId generated server-side if absent. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"sessionId":{"type":"string","description":"Session ID; generated server-side if absent"}}}}}},"responses":{"202":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"queued":{"type":"boolean"},"messageId":{"type":"string","nullable":true},"sessionId":{"type":"string"},"noAddress":{"type":"boolean","description":"True when the hotel has no address on file; the Business Console warns the operator at trigger time (AI Visibility results are less accurate without it)."}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/test/session/list":{"get":{"tags":["Legacy"],"operationId":"legacyBcTestSessionList","summary":"DEPRECATED: List test sessions","description":"DEPRECATED: Returns test sessions from the testing schema. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Array of test sessions"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/test/session/report":{"get":{"tags":["Legacy"],"operationId":"legacyBcTestSessionReport","summary":"DEPRECATED: Get test session report","description":"DEPRECATED: Returns the test session report object { id, description, tests[] } for a given session_id (accepts ?id= or ?session_id=). Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"session_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Test session report ({ id, description, tests[] })"},"400":{"description":"Missing session_id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Test session not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/test/session/gfaq":{"post":{"tags":["Legacy"],"operationId":"legacyBcTestSessionGfaq","summary":"DEPRECATED: Generate FAQ from test session","description":"DEPRECATED: Returns 202 Accepted; FAQ generation is pipeline-side. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"202":{"description":"Queued"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/subscription":{"post":{"tags":["Subscriptions"],"operationId":"subscriptionCreate","summary":"Create email subscribers (bulk)","description":"Inserts one or more rows into email_subscribers. Resolves known users by email (case-insensitive). Requires session auth.","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subscribers"],"properties":{"subscribers":{"type":"array","minItems":1,"items":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"emailType":{"type":"string"},"email_type":{"type":"string"},"clientId":{"type":"string"},"client_id":{"type":"string"}}}}}}}}},"responses":{"201":{"description":"Subscribers created"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Subscriptions"],"operationId":"subscriptionDelete","summary":"Soft-delete subscribers by id","description":"Soft-deletes email_subscriber rows. Pass comma-separated UUIDs in the ?ids= query param. Requires session auth.","security":[{"sessionAuth":[]}],"parameters":[{"in":"query","name":"ids","required":true,"schema":{"type":"string"},"description":"Comma-separated subscriber UUIDs"}],"responses":{"200":{"description":"Subscribers deleted"},"400":{"description":"Missing ids query parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/subscription/list":{"get":{"tags":["Subscriptions"],"operationId":"subscriptionList","summary":"List active subscribers for a client","description":"Returns active (non-deleted, non-unsubscribed) email_subscribers for the x-client-id client. Requires session auth.","security":[{"sessionAuth":[]}],"parameters":[{"in":"header","name":"x-client-id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of subscribers"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/subscription/unsubscribe":{"post":{"tags":["Subscriptions"],"operationId":"subscriptionUnsubscribe","summary":"Token-based email unsubscribe","description":"Public endpoint — no auth required. Sets unsubscribed_date on the email_subscribers row identified by the ?id= UUID.","parameters":[{"in":"query","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Unsubscribed or already unsubscribed"},"400":{"description":"Invalid subscription id"},"404":{"description":"Subscription not found"},"500":{"description":"Server error"}}}},"/api/legacy/user/":{"get":{"tags":["Legacy"],"operationId":"legacyBcUserGet","summary":"Legacy: Get current user","description":"Legacy: Returns the authenticated user record. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"User record"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBcUserUpdate","summary":"Legacy: Update user profile","description":"Legacy: Updates firstName, lastName, or phone for the specified user id. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"phone":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated user record"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/user/create":{"post":{"tags":["Legacy"],"operationId":"legacyBcUserCreate","summary":"DEPRECATED: Create user","description":"DEPRECATED: Inserts a minimal user record. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"}}}}}},"responses":{"201":{"description":"User created"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Duplicate email","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/user/adminsetpassword":{"put":{"tags":["Legacy"],"operationId":"legacyBcUserAdminSetPassword","summary":"DEPRECATED: Admin set password","description":"DEPRECATED: Flags force_reset_password on the user record. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string"},"new_password":{"type":"string"}}}}}},"responses":{"200":{"description":"Password flagged for reset"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/user/addroles":{"post":{"tags":["Legacy"],"operationId":"legacyBcUserAddRoles","summary":"DEPRECATED: Add roles to user","description":"DEPRECATED: Inserts user_role_links. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string"},"role_ids":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Roles added"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/user/list":{"get":{"tags":["Legacy"],"operationId":"legacyBcUserList","summary":"DEPRECATED: List users","description":"DEPRECATED: Returns up to 100 users. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Array of users"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/user/role/list":{"get":{"tags":["Legacy"],"operationId":"legacyBcUserRoleList","summary":"DEPRECATED: List roles","description":"DEPRECATED: Returns all active roles for dropdown population. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"responses":{"200":{"description":"Array of roles"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/salesagent":{"get":{"tags":["Legacy"],"operationId":"legacySalesAgentGet","summary":"Get sales agent config","description":"DEPRECATED: Returns the sales agent config (enabled flag + opportunities). Consumer: legacy/business-console, legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sales agent config","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"opportunities":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to read sales agent config","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacySalesAgentPut","summary":"Update sales agent config","description":"DEPRECATED: Updates the sales agent config. Disabling keeps the configured opportunities (never deletes them; restored on re-enable). Consumer: legacy/business-console, legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"opportunities":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Updated sales agent config"},"400":{"description":"No fields to update / Invalid enabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to update sales agent config","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/salesagent/whitelist":{"get":{"tags":["Legacy"],"operationId":"legacySalesAgentWhitelistGet","summary":"Get sales agent email whitelist","description":"DEPRECATED: Returns active SALES_AGENT_LEAD whitelist entries. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Active whitelist","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to read sales agent whitelist","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Legacy"],"operationId":"legacySalesAgentWhitelistPost","summary":"Add emails to sales agent whitelist","description":"DEPRECATED: Inserts new email rows (deduplication enforced). Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emails"],"properties":{"emails":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated whitelist with added count"},"400":{"description":"No valid emails to add","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to add whitelist entries","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Legacy"],"operationId":"legacySalesAgentWhitelistDelete","summary":"Soft-delete whitelist entries","description":"DEPRECATED: Stamps deleted_date/deleted_by on the specified rows. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Remaining active whitelist"},"400":{"description":"Provide one or more ids","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to delete whitelist entries","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/salesagent/recipients":{"get":{"tags":["Legacy"],"operationId":"legacySalesAgentRecipients","summary":"Get sales agent email recipients","description":"DEPRECATED: Returns {email} list from active SALES_AGENT_LEAD whitelist. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Recipient list","content":{"application/json":{"schema":{"type":"object","properties":{"recipients":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"}}}}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to read sales agent recipients","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/branding":{"get":{"tags":["Legacy"],"operationId":"legacyBrandingGet","summary":"Get branding config","description":"DEPRECATED: Returns the branding config (enabled flag). Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Branding config","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to read branding config","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBrandingPut","summary":"Update branding config","description":"DEPRECATED: Updates the branding config. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Invalid enabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to update branding config","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/documents/config":{"get":{"tags":["Legacy"],"operationId":"legacyDocumentsConfigGet","summary":"Get documents config","description":"DEPRECATED: Returns the documents config (enabled flag). Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Documents config","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to read documents config","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyDocumentsConfigPut","summary":"Update documents config","description":"DEPRECATED: Updates the documents config. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Invalid enabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to update documents config","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client/chatstyles":{"get":{"tags":["Legacy"],"operationId":"legacyChatStylesGet","summary":"Get chat styles","description":"DEPRECATED: Returns the chat styles config map. Consumer: legacy/business-console, legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chat styles map","content":{"application/json":{"schema":{"type":"object","properties":{"chatStyles":{"type":"object"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to read chat styles","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyChatStylesPut","summary":"Update chat styles","description":"DEPRECATED: Updates the chat styles config map. Consumer: legacy/business-console, legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chatStyles"],"properties":{"chatStyles":{"type":"object"}}}}}},"responses":{"200":{"description":"Updated chat styles"},"400":{"description":"Invalid chatStyles","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to update chat styles","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/webhooks/instagram":{"get":{"tags":["Webhooks"],"operationId":"instagramWebhookVerify","summary":"Meta webhook verification handshake","description":"Called by Meta to verify the callback URL. Echoes hub.challenge when hub.mode=subscribe and hub.verify_token matches the configured secret. Returns 403 otherwise.","parameters":[{"name":"hub.mode","in":"query","required":true,"schema":{"type":"string"},"description":"Must be 'subscribe'"},{"name":"hub.challenge","in":"query","required":true,"schema":{"type":"string"},"description":"Random string Meta expects to be echoed back"},{"name":"hub.verify_token","in":"query","required":true,"schema":{"type":"string"},"description":"Shared secret set in the Meta app dashboard"}],"responses":{"200":{"description":"Verification accepted — raw hub.challenge echoed as plain text","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Forbidden — mode is not subscribe or token does not match","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Webhooks"],"operationId":"instagramWebhookReceive","summary":"Receive Instagram DM webhook events","description":"Receives inbound Instagram DM events from Meta. Verifies the X-Hub-Signature-256 HMAC over the raw request body before processing. Distinguishes guest messages from operator message_echoes. Responds 200 immediately (fast ack). Phase 2a Sprint 1: transport only — no agent wiring.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["instagram"]},"entry":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Hotel Instagram Business Account ID"},"messaging":{"type":"array","items":{"type":"object","properties":{"sender":{"type":"object","properties":{"id":{"type":"string"}}},"recipient":{"type":"object","properties":{"id":{"type":"string"}}},"timestamp":{"type":"integer"},"message":{"type":"object","properties":{"mid":{"type":"string"},"text":{"type":"string"},"is_echo":{"type":"boolean","description":"true for operator message_echoes; absent/false for guest messages"}}}}}}}}}}}}}},"responses":{"200":{"description":"Webhook acknowledged","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Empty body or malformed JSON (after valid signature)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing or invalid X-Hub-Signature-256","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/webhooks/messenger":{"get":{"tags":["Webhooks"],"operationId":"messengerWebhookVerify","summary":"Meta Messenger webhook verification handshake","description":"Called by Meta to verify the Messenger callback URL. Echoes hub.challenge when hub.mode=subscribe and hub.verify_token matches. Returns 403 otherwise. Shares the same handler as /webhooks/instagram.","parameters":[{"name":"hub.mode","in":"query","required":true,"schema":{"type":"string"},"description":"Must be 'subscribe'"},{"name":"hub.challenge","in":"query","required":true,"schema":{"type":"string"}},{"name":"hub.verify_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification accepted — raw hub.challenge echoed as plain text","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Forbidden — mode is not subscribe or token does not match","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Webhooks"],"operationId":"messengerWebhookReceive","summary":"Receive Facebook Messenger webhook events","description":"Receives inbound Facebook Messenger page events from Meta. Verifies X-Hub-Signature-256 HMAC against META_APP_SECRET. Routes events by object field: 'page' dispatches to the Messenger handler. Responds 200 immediately.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["page"]},"entry":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Webhook acknowledged","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Empty body or malformed JSON","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing or invalid X-Hub-Signature-256","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"META_APP_SECRET not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/webhooks/whatsapp":{"get":{"tags":["Webhooks"],"operationId":"whatsappWebhookVerify","summary":"Meta WhatsApp webhook verification handshake","description":"Called by Meta to verify the WhatsApp callback URL. Echoes hub.challenge when hub.mode=subscribe and hub.verify_token matches. Returns 403 otherwise. Shares the same handler as /webhooks/instagram.","parameters":[{"name":"hub.mode","in":"query","required":true,"schema":{"type":"string"},"description":"Must be 'subscribe'"},{"name":"hub.challenge","in":"query","required":true,"schema":{"type":"string"}},{"name":"hub.verify_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification accepted — raw hub.challenge echoed as plain text","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Forbidden — mode is not subscribe or token does not match","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Webhooks"],"operationId":"whatsappWebhookReceive","summary":"Receive WhatsApp Business webhook events","description":"Receives inbound WhatsApp Business Account events from Meta. Verifies X-Hub-Signature-256 HMAC. Routes events by object field: 'whatsapp_business_account' dispatches to the WhatsApp handler. Responds 200 immediately.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["whatsapp_business_account"]},"entry":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Webhook acknowledged","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Empty body or malformed JSON","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing or invalid X-Hub-Signature-256","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"INSTAGRAM_APP_SECRET not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/dashboard/stats":{"get":{"tags":["REST API"],"operationId":"getDashboardStats","summary":"Get dashboard statistics","description":"Returns aggregate statistics for the authenticated user's dashboard view, scoped by x-client-id.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Dashboard statistics"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/dashboard/activity":{"get":{"tags":["REST API"],"operationId":"getDashboardActivity","summary":"Get dashboard activity feed","description":"Returns recent activity items for the authenticated user's dashboard, scoped by x-client-id. Supports pagination via limit (1–50, default 10).","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":10}}],"responses":{"200":{"description":"Activity feed","content":{"application/json":{"schema":{"type":"object","properties":{"activity":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid client id or query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/knowledge":{"get":{"tags":["REST API"],"operationId":"listKnowledge","summary":"List knowledge base items","description":"Returns a paginated list of knowledge base records for the specified client. Supports cursor-based pagination, full-text search, and source/date filters.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Client UUID to scope the query"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"after","in":"query","required":false,"schema":{"type":"string"},"description":"Cursor for pagination"},{"name":"includeDeleted","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"},"description":"Full-text search query"},{"name":"filter_source","in":"query","required":false,"schema":{"type":"string","enum":["Website","Document","User"]}},{"name":"filter_created_from","in":"query","required":false,"schema":{"type":"number"},"description":"Epoch ms lower bound for created_date"},{"name":"filter_created_to","in":"query","required":false,"schema":{"type":"number"},"description":"Epoch ms upper bound for created_date"}],"responses":{"200":{"description":"Knowledge item list","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}},"paginationToken":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences":{"get":{"tags":["REST API"],"operationId":"listExperiences","summary":"List experiences","description":"Returns a paginated list of experiences for the authenticated client. Supports cursor-based pagination and sorting.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"after","in":"query","required":false,"schema":{"type":"string"},"description":"Cursor for pagination"}],"responses":{"200":{"description":"Experience list"},"400":{"description":"Invalid client id or query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["REST API"],"operationId":"createExperience","summary":"Create an experience","description":"Creates a new experience for the client identified by x-client-id.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","category"],"properties":{"title":{"type":"string"},"category":{"type":"string","enum":["wellness","activity","excursion","rental","transfer"]},"shortDesc":{"type":"string"},"longDesc":{"type":"string"},"basePrice":{"type":"number"},"currency":{"type":"string"},"location":{"type":"string"},"duration":{"type":"integer"},"inventoryModel":{"type":"string","enum":["slots","per_unit"]},"slots":{"type":"integer"},"slotCapacity":{"type":"integer"},"daysOpen":{"type":"array","items":{"type":"string"}},"leadTime":{"type":"integer"},"partySize":{"type":"object"},"cancellation":{"type":"object"},"includes":{"type":"array","items":{"type":"string"}},"bring":{"type":"array","items":{"type":"string"}},"knowBefore":{"type":"array","items":{"type":"string"}},"aiNotes":{"type":"string"},"meetingType":{"type":"string"},"meetingDetail":{"type":"string"},"unitsTotal":{"type":"integer"},"operatingHoursOpen":{"type":"string"},"operatingHoursClose":{"type":"string"},"propertyId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Experience created"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences/agent":{"post":{"tags":["REST API"],"operationId":"experienceAgent","summary":"Send a message to the experience agent","description":"Sends a message to the AI experience agent with context about catalog, detail, bookings, guests, or inbox. Returns an agent response. Requires experiences:READ permission.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message","context"],"properties":{"message":{"type":"string","minLength":1,"maxLength":5000},"context":{"type":"string","enum":["catalog","detail","bookings","guests","inbox"]},"experienceId":{"type":"string","format":"uuid"},"attachmentUrl":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Agent response"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences/{id}":{"get":{"tags":["REST API"],"operationId":"getExperience","summary":"Get an experience","description":"Returns the full detail of a single experience by its UUID.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Experience detail"},"400":{"description":"Invalid experience id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["REST API"],"operationId":"updateExperience","summary":"Update an experience","description":"Updates the fields of an existing experience.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated experience"},"400":{"description":"Invalid experience id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["REST API"],"operationId":"archiveExperience","summary":"Archive (soft-delete) an experience","description":"Soft-deletes an experience. The record remains in the database but is hidden from listings.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Experience archived"},"400":{"description":"Invalid experience id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences/{id}/publish":{"post":{"tags":["REST API"],"operationId":"publishExperience","summary":"Publish an experience","description":"Marks an experience as published. Returns 422 if the experience does not meet the sellable gate requirements (missing required fields for booking).","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Experience published"},"400":{"description":"Invalid experience id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"422":{"description":"Experience does not meet sellable gate requirements","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences/{id}/unpublish":{"post":{"tags":["REST API"],"operationId":"unpublishExperience","summary":"Unpublish an experience","description":"Marks an experience as unpublished (draft). Hides it from guest-facing surfaces.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Experience unpublished"},"400":{"description":"Invalid experience id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences/{id}/variants":{"post":{"tags":["REST API"],"operationId":"addExperienceVariant","summary":"Add a variant to an experience","description":"Adds a pricing variant to an experience (e.g. Early Bird, Standard, Premium).","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label","price"],"properties":{"label":{"type":"string"},"price":{"type":"number"},"default":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Variant added"},"400":{"description":"Invalid experience id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences/{id}/customertypes":{"post":{"tags":["REST API"],"operationId":"addExperienceCustomerType","summary":"Add a customer type to an experience","description":"Adds a customer type (Adult, Child, Senior, etc.) with its own pricing to an experience.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label"],"properties":{"label":{"type":"string"},"ageRange":{"type":"object"},"price":{"type":"number"},"maxPerBooking":{"type":"integer"}}}}}},"responses":{"201":{"description":"Customer type added"},"400":{"description":"Invalid experience id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/experiences/{id}/availability":{"get":{"tags":["REST API"],"operationId":"getExperienceAvailability","summary":"Get experience availability","description":"Returns availability slots for an experience within the specified date range.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"Start date (YYYY-MM-DD)"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"End date (YYYY-MM-DD)"}],"responses":{"200":{"description":"Availability data"},"400":{"description":"Invalid experience id or date params","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["REST API"],"operationId":"updateExperienceAvailability","summary":"Update experience availability","description":"Updates the availability for a specific date: block/unblock the date and override slot counts.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["date"],"properties":{"date":{"type":"string","format":"date"},"blocked":{"type":"boolean"},"blockReason":{"type":"string"},"slotOverrides":{"type":"object"}}}}}},"responses":{"200":{"description":"Availability updated"},"400":{"description":"Invalid experience id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Experience not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/bookings":{"get":{"tags":["REST API"],"operationId":"listBookings","summary":"List bookings","description":"Returns a paginated list of bookings. Supports filtering by status, channel, experience, and property.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"after","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["held","confirmed","cancelled","completed"]}},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["webchat","sms","front_desk","phone","email","agent"]}},{"name":"experience_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"property_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Booking list"},"400":{"description":"Invalid client id or query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["REST API"],"operationId":"createBooking","summary":"Create a booking","description":"Creates a new booking (hold). Returns 409 if capacity for the requested slot is exhausted.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["experienceId","date","channel"],"properties":{"experienceId":{"type":"string","format":"uuid"},"date":{"type":"string","format":"date"},"slot":{"type":"string"},"variantId":{"type":"string","format":"uuid"},"party":{"type":"array","items":{"type":"object"}},"guestName":{"type":"string"},"guestEmail":{"type":"string","format":"email"},"guestRoom":{"type":"string"},"channel":{"type":"string","enum":["webchat","sms","front_desk","phone","email","agent"]},"specialRequest":{"type":"string"},"idempotencyKey":{"type":"string"}}}}}},"responses":{"201":{"description":"Booking created (held)"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Capacity exhausted for the requested slot","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/bookings/{id}":{"delete":{"tags":["REST API"],"operationId":"cancelBooking","summary":"Cancel a booking","description":"Cancels a booking. An optional reason may be provided in the request body.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string"}}}}}},"responses":{"204":{"description":"Booking cancelled"},"400":{"description":"Invalid booking id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Booking not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/bookings/{id}/confirm":{"post":{"tags":["REST API"],"operationId":"confirmBooking","summary":"Confirm a held booking","description":"Confirms a booking that is in the 'held' state. Returns 409 if the hold has expired.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Booking confirmed"},"400":{"description":"Invalid booking id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Booking not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Hold has expired; booking must be recreated","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/guests":{"get":{"tags":["REST API"],"operationId":"listGuests","summary":"List guests","description":"Returns a paginated list of guests for the client. Supports search and sorting.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"after","in":"query","required":false,"schema":{"type":"string"}},{"name":"property_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","enum":["last_name","created_date"]}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Guest list"},"400":{"description":"Invalid client id or query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/guests/{id}":{"get":{"tags":["REST API"],"operationId":"getGuest","summary":"Get a guest","description":"Returns the profile of a single guest by UUID.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Guest profile"},"400":{"description":"Invalid guest id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Guest not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/analytics":{"get":{"tags":["REST API"],"operationId":"listAnalyticsRuns","summary":"List analytics runs","description":"Returns a paginated list of analytics run history. Supports filtering by type and status.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"clientId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["CHAT_LOGS","AI_VISIBILITY"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["QUEUED","IN_PROGRESS","ERROR","DONE"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"after","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Analytics run list"},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/analytics/{analyticsId}/rerun":{"post":{"tags":["REST API"],"operationId":"rerunAnalytics","summary":"Re-run an analytics job","description":"Schedules a re-run of the specified analytics job. Returns 202 Accepted with the new analyticsId. Returns 404 if the original run is not found.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"analyticsId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","format":"uuid"}}}}}},"responses":{"202":{"description":"Re-run scheduled","content":{"application/json":{"schema":{"type":"object","properties":{"analyticsId":{"type":"string"},"scheduled":{"type":"boolean"},"failed":{"type":"array","items":{"type":"string"},"description":"Any client IDs that failed to schedule"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Analytics run not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/analytics/{analyticsId}/report":{"get":{"tags":["REST API"],"operationId":"getAnalyticsReport","summary":"Download an analytics report","description":"Streams the analytics report file from S3. Supports html and xlsx formats via the format query parameter. Returns 404 if the run is not found.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"analyticsId","in":"path","required":true,"schema":{"type":"string"}},{"name":"clientId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["html","xlsx"]}}],"responses":{"200":{"description":"Report file stream"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Analytics run or report not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/oauth/rezstream/connect":{"get":{"tags":["REST API"],"operationId":"rezstreamConnect","summary":"Initiate rezStream OAuth connect","description":"Redirects the browser to the rezStream OAuth authorize URL. Requires a valid clientId query parameter and an authenticated session with PMS write permission. Returns 503 if the rezStream integration is not configured.","security":[{"sessionAuth":[]}],"parameters":[{"name":"clientId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Maison client UUID to connect rezStream for"}],"responses":{"302":{"description":"Redirect to rezStream OAuth authorize URL"},"400":{"description":"Missing or invalid clientId","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"rezStream integration not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/oauth/rezstream/callback":{"get":{"tags":["REST API"],"operationId":"rezstreamCallback","summary":"Handle rezStream OAuth callback","description":"Receives the authorization code and state from rezStream. Validates the HMAC-signed state, exchanges the code for tokens, and saves the integration config. Returns 400 if params are missing or invalid, 503 if not configured.","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"},"description":"Authorization code from rezStream"},{"name":"state","in":"query","required":true,"schema":{"type":"string"},"description":"HMAC-signed state parameter (contains clientId)"}],"responses":{"302":{"description":"Redirect to console on success"},"400":{"description":"Missing or invalid code/state parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"rezStream integration not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/clients":{"get":{"tags":["Users"],"operationId":"getUserClients","summary":"List clients for a user","description":"Returns a paginated list of clients the specified user has access to. Requires authentication.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Client list for the user","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}}}}},"400":{"description":"Invalid user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/roles":{"get":{"tags":["Users"],"operationId":"getUserRoles","summary":"List roles for a user","description":"Returns all roles assigned to the specified user. Returns 404 if user not found.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"responses":{"200":{"description":"User roles"},"400":{"description":"Invalid user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/groups":{"get":{"tags":["Users"],"operationId":"getUserGroups","summary":"List groups for a user","description":"Returns all user groups the specified user is a member of. Returns 404 if user not found.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"responses":{"200":{"description":"User groups"},"400":{"description":"Invalid user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/users/{id}/apikeys":{"get":{"tags":["Users"],"operationId":"getUserApiKeys","summary":"List API keys for a user","description":"Returns all API keys belonging to the specified user. Returns 404 if user not found.","security":[{"sessionAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"User UUID"}],"responses":{"200":{"description":"User API keys"},"400":{"description":"Invalid user id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/tone":{"get":{"tags":["Legacy"],"operationId":"legacyBcToneGet","summary":"Legacy: Get chatbot tone","description":"Legacy: Returns the chatbot tone prompt string for the client. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chatbot tone","content":{"application/json":{"schema":{"type":"object","properties":{"chatbotTone":{"type":"string"}}}}}},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBcToneUpdate","summary":"Legacy: Update chatbot tone","description":"Legacy: Updates the chatbot tone prompt for the client. Empty/whitespace resets to the default tone. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chatbotTone":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated chatbot tone","content":{"application/json":{"schema":{"type":"object","properties":{"chatbotTone":{"type":"string"}}}}}},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/website/{id}":{"put":{"tags":["Legacy"],"operationId":"legacyBcWebsiteUpdateSingle","summary":"Legacy: Update a website source","description":"Legacy: Updates syncSchedule and/or updateClientWebsite flag for a specific website source by websiteId. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"syncSchedule":{"type":"string","enum":["NONE","DAILY","WEEKLY","BI_WEEKLY","MONTHLY"]},"updateClientWebsite":{"type":"boolean"}}}}}},"responses":{"204":{"description":"Updated"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Legacy"],"operationId":"legacyBcWebsiteDeleteSingle","summary":"Legacy: Remove a website source","description":"Legacy: Soft-deletes the client_knowledge_source_link for the given websiteId. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Website source removed"},"400":{"description":"Invalid client id or website id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/qa/":{"get":{"tags":["Legacy"],"operationId":"legacyBcQaList","summary":"Legacy: List QA pairs","description":"Legacy: Returns paginated QA pairs. Supports full-text query, id filter, includeDeleted, deletedOnly. Consumer: legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"qa-editor","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"paginationtoken","in":"query","required":false,"schema":{"type":"string"}},{"name":"ids","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated QA pair ids"},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"Full-text search query (mutually exclusive with ids)"},{"name":"includedeleted","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"deletedonly","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"QA pair list","content":{"application/json":{"schema":{"type":"object","properties":{"qa":{"type":"array","items":{"type":"object"}},"paginationToken":{"type":"string","nullable":true}}}}}},"400":{"description":"Invalid client id, query params, or both ids and query provided","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/qa":{"post":{"tags":["Legacy"],"operationId":"legacyBcQaCreate","summary":"Legacy: Create QA pairs","description":"Legacy: Creates one or more QA pairs. Consumer: legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"qa-editor","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"QA pairs created"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBcQaUpdate","summary":"Legacy: Update QA pairs","description":"Legacy: Updates one or more QA pairs. Consumer: legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"qa-editor","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"QA pairs updated"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Legacy"],"operationId":"legacyBcQaDelete","summary":"Legacy: Delete QA pairs","description":"Legacy: Soft-deletes one or more QA pairs. Consumer: legacy/qa-editor.","deprecated":true,"x-legacy-consumer":"qa-editor","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"QA pairs deleted"},"400":{"description":"Invalid client id or request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/document":{"get":{"tags":["Legacy"],"operationId":"legacyBcDocumentList","summary":"Legacy: List documents","description":"Legacy: Returns documents linked to the client. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of documents"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"tags":["Legacy"],"operationId":"legacyBcDocumentCreate","summary":"Legacy: Upload a document","description":"Legacy: Uploads a document file (PDF, DOCX, etc.) to S3 and creates a knowledge source link for the client. Accepts multipart/form-data. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"title":{"type":"string"},"language":{"type":"string"}}}}}},"responses":{"201":{"description":"Document uploaded and knowledge link created"},"400":{"description":"Invalid client id or missing file","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Document storage not provisioned","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/document/{id}":{"get":{"tags":["Legacy"],"operationId":"legacyBcDocumentGet","summary":"Legacy: Get a document","description":"Legacy: Returns the document record and metadata for the specified document id. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document record"},"400":{"description":"Invalid client id or document id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Document not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"put":{"tags":["Legacy"],"operationId":"legacyBcDocumentUpdate","summary":"Legacy: Update a document","description":"Legacy: Replaces or updates a document file and/or its metadata. Accepts multipart/form-data. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"title":{"type":"string"},"language":{"type":"string"}}}}}},"responses":{"200":{"description":"Document updated"},"400":{"description":"Invalid client id or document id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Document not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Legacy"],"operationId":"legacyBcDocumentDelete","summary":"Legacy: Delete a document","description":"Legacy: Soft-deletes the document and its knowledge source link. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Document deleted"},"400":{"description":"Invalid client id or document id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Document not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/document/{id}/sync":{"put":{"tags":["Legacy"],"operationId":"legacyBcDocumentSync","summary":"Legacy: Trigger document sync","description":"Legacy: Triggers reprocessing/re-ingestion of the document into the knowledge base. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Sync queued"},"400":{"description":"Invalid client id or document id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Document not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/document/{id}/versions":{"get":{"tags":["Legacy"],"operationId":"legacyBcDocumentVersions","summary":"Legacy: List document versions","description":"Legacy: Returns the version history for a document from the KB version history table. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document versions"},"400":{"description":"Invalid client id or document id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Document not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client/asset/list":{"get":{"tags":["Legacy"],"operationId":"legacyBcClientAssetList","summary":"Legacy: List client assets","description":"Legacy: Returns the client asset list. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Asset list"},"400":{"description":"Invalid client id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/client/asset/{id}":{"put":{"tags":["Legacy"],"operationId":"legacyBcClientAssetUpdate","summary":"Legacy: Update client asset metadata","description":"Legacy: Updates the description or published flag of a library asset. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"},"published":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Asset updated"},"400":{"description":"Invalid client id or asset id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"tags":["Legacy"],"operationId":"legacyBcClientAssetDeleteById","summary":"Legacy: Delete a client asset by id","description":"Legacy: Deletes a client library asset by id. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Asset deleted"},"400":{"description":"Invalid client id or asset id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/user/removeroles":{"put":{"tags":["Legacy"],"operationId":"legacyBcUserRemoveRoles","summary":"Legacy: Remove roles from user","description":"Legacy: Removes the specified role assignments from a user. Target can be identified by userId or email; omitting both defaults to the current authenticated user. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"roles":{"type":"array","items":{"type":"object","properties":{"roleId":{"type":"string"},"clientId":{"type":"string","format":"uuid"}}}}}}}}},"responses":{"200":{"description":"Roles removed"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/user/{id}":{"get":{"tags":["Legacy"],"operationId":"legacyBcUserGetById","summary":"Legacy: Get user by id","description":"Legacy: Returns the user record for the specified user id including roles. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"User UUID"}],"responses":{"200":{"description":"User record with roles"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to process request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/pms/services":{"get":{"tags":["Legacy"],"operationId":"legacyBcPmsServices","summary":"Legacy: Get Mews bookable services","description":"Legacy: Fetches Mews bookable services with availability for the client. Requires hotel-config READ permission and the hotel-config feature entitlement. Consumer: legacy/business-console.","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"refresh","in":"query","required":false,"schema":{"type":"string"},"description":"Pass 'true' to bypass cache"},{"name":"startdate","in":"query","required":false,"schema":{"type":"string"}},{"name":"enddate","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"string"},"description":"Max number of services to return (default 20)"}],"responses":{"200":{"description":"Mews services list","content":{"application/json":{"schema":{"type":"object","properties":{"services":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Not Mews provider or token not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"PMS configuration not found for client","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to fetch Mews services","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/legacy/pms/getRatePlans":{"get":{"tags":["Legacy"],"operationId":"legacyBcPmsGetRatePlans","summary":"Legacy: Get Mews rate plans","description":"Legacy: Fetches Mews rate plans for the specified service ids. Requires hotel-config READ permission. Consumer: legacy/business-console. Note: path uses camelCase (legacy convention preserved).","deprecated":true,"x-legacy-consumer":"business-console","security":[{"sessionAuth":[]}],"parameters":[{"name":"x-client-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"serviceids","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated Mews service ids"}],"responses":{"200":{"description":"Rate plans for the specified services"},"400":{"description":"Invalid client id or missing serviceids","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"PMS configuration not found for client","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Unable to fetch rate plans","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/tools/sitecheck":{"post":{"tags":["Tools"],"operationId":"siteCheck","summary":"Analyze a website for Maison embed status","description":"Fetches the given URL, detects the framework, and checks whether the Maison chat widget is properly embedded.","security":[{"apiKey":[]},{"sessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteCheckBody"}}}},"responses":{"200":{"description":"Analysis result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteCheckResponse"}}}},"400":{"description":"Invalid URL or private IP blocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"URL could not be fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/diagnostic":{"post":{"tags":["Diagnostic"],"operationId":"startDiagnostic","summary":"Start a site diagnostic run","description":"Start a diagnostic check of a website. Checks whether Maison is correctly installed on the site and how it is configured, and produces findings with suggested fixes. Returns immediately; progress and results arrive on the real-time channel included in the response and in the session history. If a check is already in progress for the same site, the response indicates it so you can follow along. Checks of the same site share one session and history.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticStartBody"}}}},"responses":{"202":{"description":"Diagnostic run started (or already running)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticStartResponse"}}}},"400":{"description":"Invalid URL or malformed request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (5/IP/min)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/diagnostic/{sessionid}":{"get":{"tags":["Diagnostic"],"operationId":"getDiagnosticSession","summary":"Get diagnostic session events","description":"Returns all stored events for the session. An empty events array is valid (session not yet started).","security":[],"parameters":[{"name":"sessionid","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Opaque session identifier returned by the start-diagnostic response"}}],"responses":{"200":{"description":"Session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticSessionResponse"}}}},"400":{"description":"Invalid sessionid format","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (30/IP/min)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/diagnostic/{sessionid}/chat":{"post":{"tags":["Diagnostic"],"operationId":"diagnosticChat","summary":"Send a follow-up chat message to the diagnostic agent","description":"Send a follow-up question about the diagnostic findings for a site. Returns the agent's reply. The sessionId must match an existing diagnostic session.","security":[],"parameters":[{"name":"sessionid","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Opaque session identifier returned by the start-diagnostic response"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticChatBody"}}}},"responses":{"200":{"description":"Chat assistant reply","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticChatResponse"}}}},"400":{"description":"Invalid sessionid or malformed request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No diagnostic session found for this sessionid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (10/IP/min)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The analysis service was unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"TextPart":{"type":"object","required":["type","text"],"properties":{"type":{"type":"string","enum":["text"]},"text":{"type":"string"}}},"Message":{"type":"object","required":["role","parts"],"properties":{"role":{"type":"string","enum":["user","agent"]},"parts":{"type":"array","items":{"$ref":"#/components/schemas/TextPart"},"minItems":1}}},"Artifact":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"parts":{"type":"array","items":{"$ref":"#/components/schemas/TextPart"},"minItems":1},"index":{"type":"integer","minimum":0,"default":0}},"required":["parts"]},"TaskStatus":{"type":"object","required":["state","timestamp"],"properties":{"state":{"type":"string","enum":["submitted","working","completed","failed","canceled"]},"message":{"$ref":"#/components/schemas/Message"},"timestamp":{"type":"string"}}},"Task":{"type":"object","required":["id","clientId","status"],"properties":{"id":{"type":"string"},"clientId":{"type":"string"},"status":{"$ref":"#/components/schemas/TaskStatus"},"artifacts":{"type":"array","items":{"$ref":"#/components/schemas/Artifact"}},"history":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"metadata":{"type":"object","additionalProperties":true},"expiresAt":{"type":"integer"}}},"JsonRpcRequest":{"type":"object","required":["jsonrpc","id","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"number"}]},"method":{"type":"string"},"params":{"type":"object","additionalProperties":true}}},"JsonRpcResponse":{"type":"object","required":["jsonrpc","id"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"number"}]},"result":{},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{}},"required":["code","message"]}}},"ChatMessage":{"type":"object","required":["role","message","datetime"],"properties":{"role":{"type":"string","enum":["assistant","user","system"]},"message":{"type":"string"},"datetime":{"oneOf":[{"type":"string"},{"type":"number"}]},"isOpeningMessage":{"type":"boolean"},"isAdmin":{"type":"boolean"},"context":{"type":"array","items":{"type":"string"}},"type":{"type":"string"},"locale":{"type":"string"},"isTestSession":{"type":"boolean"}}},"QueryBody":{"type":"object","required":["id","query","messages"],"properties":{"id":{"type":"string","description":"Session ID"},"query":{"type":"string","description":"User's query text"},"localTime":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"pmsConfig":{"type":"object","nullable":true,"properties":{"pmsProvider":{"type":"string"},"propertyConfig":{"type":"array","items":{"type":"object"}},"serviceConfig":{"type":"array","items":{"type":"object"}},"rateConfig":{"type":"array","items":{"type":"object"}}}},"messageToken":{"type":"string"}}},"ApiKeyCreateBody":{"type":"object","properties":{"description":{"type":"string","default":"API key"}}},"ApiKeyCreateResponse":{"type":"object","required":["key","masked","description","userId"],"properties":{"key":{"type":"string","description":"Full API key — shown once, store securely"},"masked":{"type":"string","description":"Masked key for display"},"description":{"type":"string"},"userId":{"type":"string"}}},"McpQueryHotelParams":{"type":"object","required":["clientId","query"],"properties":{"clientId":{"type":"string","description":"Client/tenant ID"},"query":{"type":"string","description":"The question to ask"},"sessionId":{"type":"string","description":"Existing session ID to continue a conversation"},"locale":{"type":"string","description":"Locale code (e.g. en, fr, de)"}}},"McpGetSessionParams":{"type":"object","required":["clientId","sessionId"],"properties":{"clientId":{"type":"string","description":"Client/tenant ID"},"sessionId":{"type":"string","description":"Session ID to retrieve"}}},"McpCreateSessionParams":{"type":"object","required":["clientId"],"properties":{"clientId":{"type":"string","description":"Client/tenant ID"},"locale":{"type":"string","description":"Locale code"}}},"McpGetClientInfoParams":{"type":"object","required":["clientId","fields"],"properties":{"clientId":{"type":"string","description":"Client/tenant ID"},"fields":{"type":"string","description":"Comma-separated field paths (e.g. hotelConfig.name,clientAssets.icon)"},"locale":{"type":"string","description":"Locale code for translation fields"}}},"McpListTranslationsParams":{"type":"object","required":["clientId","keys"],"properties":{"clientId":{"type":"string","description":"Client/tenant ID"},"keys":{"type":"string","description":"Comma-separated translation key names, or '*' for all"},"locales":{"type":"string","description":"Comma-separated locale codes, or '*' for all"}}},"McpListClientsParams":{"type":"object","properties":{"search":{"type":"string","description":"Filter by name, description, or website domain"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Results per page"},"after":{"type":"string","description":"Cursor for next page"},"order_by":{"type":"string","enum":["name","created_date","website_id","demo_client","last_scraped_date","ai_visibility_schedule"],"default":"created_date","description":"Sort column"},"sort":{"type":"string","enum":["ASC","DESC"],"default":"DESC","description":"Sort direction"}}},"McpGetClientParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Client ID (UUID)"}}},"McpCreateClientParams":{"type":"object","required":["name","website_id"],"properties":{"name":{"type":"string","description":"Client display name"},"website_id":{"type":"string","format":"uuid","description":"Associated website UUID"},"demo_client":{"type":"boolean","default":false,"description":"Whether this is a demo client"},"description":{"type":"string","nullable":true,"default":null,"description":"Optional description"},"scrape_language":{"type":"string","nullable":true,"default":null,"description":"Language code for scraping"},"chat_logs_analytics_schedule":{"type":"string","enum":["NONE","DAILY","WEEKLY","BI_WEEKLY","MONTHLY"],"default":"NONE","description":"Analytics schedule"},"ai_visibility_schedule":{"type":"string","enum":["NONE","DAILY","WEEKLY","BI_WEEKLY","MONTHLY"],"default":"NONE","description":"AI visibility schedule"}}},"McpUpdateClientParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Client ID (UUID) to update"},"name":{"type":"string","description":"New display name"},"website_id":{"type":"string","format":"uuid","description":"New website UUID"},"demo_client":{"type":"boolean","description":"Set demo flag"},"description":{"type":"string","nullable":true,"description":"New description"},"scrape_language":{"type":"string","nullable":true,"description":"New scrape language"},"chat_logs_analytics_schedule":{"type":"string","enum":["NONE","DAILY","WEEKLY","BI_WEEKLY","MONTHLY"],"description":"New analytics schedule"},"ai_visibility_schedule":{"type":"string","enum":["NONE","DAILY","WEEKLY","BI_WEEKLY","MONTHLY"],"description":"New AI visibility schedule"}}},"McpDisableClientParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Client ID (UUID) to disable"}}},"McpListUsersParams":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Results per page"},"after":{"type":"string","description":"Cursor for next page"},"search":{"type":"string","description":"Filter by name or email"},"status":{"type":"string","enum":["active","disabled","invited","expired"],"description":"Filter by status"},"order_by":{"type":"string","enum":["email","last_name","status","last_login_date","created_date"],"default":"created_date","description":"Sort column"},"sort":{"type":"string","enum":["ASC","DESC"],"default":"DESC","description":"Sort direction"}}},"McpGetUserParams":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","description":"User ID (UUID)"}}},"McpInviteUserParams":{"type":"object","required":["email","first_name","last_name"],"properties":{"email":{"type":"string","format":"email","description":"Email address"},"first_name":{"type":"string","description":"First name"},"last_name":{"type":"string","description":"Last name"},"invite_expiry_days":{"type":"integer","minimum":1,"maximum":90,"default":7,"description":"Days until invite expires"}}},"McpUpdateUserParams":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","description":"User ID (UUID) to update"},"first_name":{"type":"string","description":"New first name"},"last_name":{"type":"string","description":"New last name"},"phone":{"type":"string","nullable":true,"description":"Phone number (null to clear)"},"enable":{"type":"boolean","description":"Set true to re-enable a disabled user"}}},"McpDisableUserParams":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","description":"User ID (UUID) to disable"}}},"McpReinviteUserParams":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","description":"User ID (UUID) to reinvite"},"invite_expiry_days":{"type":"integer","minimum":1,"maximum":90,"default":7,"description":"Days until new invite expires"}}},"McpForceResetUserParams":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","description":"User ID (UUID) to force reset"}}},"McpGetUserActivityParams":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","description":"User ID (UUID)"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Events per page"},"after":{"type":"string","description":"Cursor for next page"}}},"McpListRolesParams":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Results per page"},"after":{"type":"string","description":"Cursor for next page"},"search":{"type":"string","description":"Filter by name or description"},"order_by":{"type":"string","enum":["name","created_date"],"default":"created_date","description":"Sort column"},"sort":{"type":"string","enum":["ASC","DESC"],"default":"DESC","description":"Sort direction"}}},"McpGetRoleParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Role ID (UUID)"}}},"McpCreateRoleParams":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Role name"},"description":{"type":"string","description":"Optional description"},"client_id":{"type":"string","format":"uuid","description":"Client ID to scope role"},"visibility_maison_only":{"type":"boolean","description":"Only visible to Maison admins"}}},"McpUpdateRoleParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Role ID (UUID) to update"},"name":{"type":"string","description":"New role name"},"description":{"type":"string","description":"New description"},"visibility_maison_only":{"type":"boolean","description":"Only visible to Maison admins"}}},"McpDisableRoleParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Role ID (UUID) to disable"}}},"McpAddRolePolicyParams":{"type":"object","required":["role_id","permission"],"properties":{"role_id":{"type":"string","description":"Role ID (UUID)"},"feature_id":{"type":"string","format":"uuid","description":"Feature ID restriction"},"client_id":{"type":"string","format":"uuid","description":"Client ID restriction"},"client_region_id":{"type":"string","format":"uuid","description":"Client region ID restriction"},"client_department_id":{"type":"string","format":"uuid","description":"Client department ID restriction"},"tag_id":{"type":"string","format":"uuid","description":"Tag ID restriction"},"permission":{"type":"string","enum":["READ","WRITE","EXECUTE","DENY"],"description":"Permission level"}}},"McpRemoveRolePolicyParams":{"type":"object","required":["role_id","policy_id"],"properties":{"role_id":{"type":"string","description":"Role ID (UUID)"},"policy_id":{"type":"string","description":"Policy ID (UUID) to remove"}}},"McpGetRoleUsersParams":{"type":"object","required":["role_id"],"properties":{"role_id":{"type":"string","description":"Role ID (UUID)"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Results per page"},"after":{"type":"string","description":"Cursor for next page"}}},"McpGetRoleGroupsParams":{"type":"object","required":["role_id"],"properties":{"role_id":{"type":"string","description":"Role ID (UUID)"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Results per page"},"after":{"type":"string","description":"Cursor for next page"}}},"McpListFeaturesParams":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Results per page"},"after":{"type":"string","description":"Cursor for next page"},"search":{"type":"string","description":"Filter by name or description"}}},"McpCreateFeatureParams":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Feature name"},"description":{"type":"string","description":"Optional description"}}},"McpUpdateFeatureParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Feature ID (UUID) to update"},"name":{"type":"string","description":"New feature name"},"description":{"type":"string","description":"New description"}}},"McpDeprecateFeatureParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Feature ID (UUID) to deprecate"}}},"McpListUserGroupsParams":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Results per page"},"after":{"type":"string","description":"Cursor for next page"},"search":{"type":"string","description":"Filter by name or description"},"order_by":{"type":"string","enum":["name","member_count","created_date"],"default":"created_date","description":"Sort column"},"sort":{"type":"string","enum":["ASC","DESC"],"default":"DESC","description":"Sort direction"}}},"McpGetUserGroupParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Group ID (UUID)"}}},"McpCreateUserGroupParams":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Group name"},"description":{"type":"string","description":"Optional description"},"client_id":{"type":"string","format":"uuid","description":"Client ID to scope group"}}},"McpUpdateUserGroupParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Group ID (UUID) to update"},"name":{"type":"string","description":"New group name"},"description":{"type":"string","description":"New description"}}},"McpDeleteUserGroupParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Group ID (UUID) to delete"}}},"McpUpdateGroupMembersParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Group ID (UUID)"},"add":{"type":"array","items":{"type":"string","format":"uuid"},"description":"User IDs to add"},"remove":{"type":"array","items":{"type":"string","format":"uuid"},"description":"User IDs to remove"}}},"McpUpdateGroupRolesParams":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Group ID (UUID)"},"add":{"type":"array","items":{"type":"object","properties":{"role_id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"}}},"description":"Role assignments to add"},"remove":{"type":"array","items":{"type":"object","properties":{"role_id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"}}},"description":"Role assignments to remove"}}},"McpListRegionsParams":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Page size"},"after":{"type":"string","description":"Cursor for next page"},"search":{"type":"string","description":"Search by name or description"}}},"McpCreateRegionParams":{"type":"object","required":["client_id","name"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"name":{"type":"string","description":"Region name"},"description":{"type":"string","description":"Optional description"}}},"McpUpdateRegionParams":{"type":"object","required":["client_id","region_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"region_id":{"type":"string","description":"Region ID (UUID) to update"},"name":{"type":"string","description":"New region name"},"description":{"type":"string","description":"New description"}}},"McpDeleteRegionParams":{"type":"object","required":["client_id","region_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"region_id":{"type":"string","description":"Region ID (UUID) to disable"}}},"McpListDepartmentsParams":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Page size"},"after":{"type":"string","description":"Cursor for next page"},"search":{"type":"string","description":"Search by name or description"}}},"McpCreateDepartmentParams":{"type":"object","required":["client_id","name"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"name":{"type":"string","description":"Department name"},"description":{"type":"string","description":"Optional description"}}},"McpUpdateDepartmentParams":{"type":"object","required":["client_id","department_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"department_id":{"type":"string","description":"Department ID (UUID) to update"},"name":{"type":"string","description":"New department name"},"description":{"type":"string","description":"New description"}}},"McpDeleteDepartmentParams":{"type":"object","required":["client_id","department_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"department_id":{"type":"string","description":"Department ID (UUID) to disable"}}},"McpListTagsParams":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Page size"},"after":{"type":"string","description":"Cursor for next page"},"search":{"type":"string","description":"Search by name or description"}}},"McpCreateTagParams":{"type":"object","required":["client_id","name"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"name":{"type":"string","description":"Tag name"},"description":{"type":"string","description":"Optional description"}}},"McpUpdateTagParams":{"type":"object","required":["client_id","tag_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"tag_id":{"type":"string","description":"Tag ID (UUID) to update"},"name":{"type":"string","description":"New tag name"},"description":{"type":"string","description":"New description"}}},"McpDeleteTagParams":{"type":"object","required":["client_id","tag_id"],"properties":{"client_id":{"type":"string","description":"Client UUID"},"tag_id":{"type":"string","description":"Tag ID (UUID) to delete"}}},"McpListClientPipelineTasksParams":{"type":"object","required":["clientId"],"properties":{"clientId":{"type":"string","description":"Client UUID to list running pipeline tasks for"}}},"McpStopClientPipelineTaskParams":{"type":"object","required":["clientId","taskId"],"properties":{"clientId":{"type":"string","description":"Client UUID that owns the pipeline task"},"taskId":{"type":"string","pattern":"^[0-9a-f]{32}$","description":"Pipeline task identifier (32 lowercase hex characters)"}}},"SiteCheckBody":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"The website URL to analyze","example":"https://myhotel.com"}},"example":{"url":"https://myhotel.com"}},"ClientIdCheck":{"type":"object","description":"Extraction + classification of the clientId embedded on the analyzed page. Defect statuses name real copy mistakes (stray whitespace, commas, truncation); corrected carries the best-guess corrected value when the defect is inferable and the result would be a valid UUID.","properties":{"raw":{"type":"string","nullable":true},"status":{"type":"string","enum":["valid","whitespace","embedded_comma","truncated","not_a_uuid","missing"]},"corrected":{"type":"string","nullable":true}}},"SiteCheckResponse":{"type":"object","properties":{"url":{"type":"string"},"fetchable":{"type":"boolean"},"framework":{"type":"string"},"hasAgentScript":{"type":"boolean"},"scriptPlacement":{"type":"string","nullable":true,"enum":["head","body"]},"hasInitCall":{"type":"boolean"},"initCorrect":{"type":"boolean"},"clientIdPresent":{"type":"boolean"},"clientId":{"$ref":"#/components/schemas/ClientIdCheck"},"diagnosis":{"type":"string","enum":["not_embedded","init_missing","already_correct","partial"]},"suggestedPlatformGuide":{"type":"string"},"scriptReachable":{"type":"boolean","nullable":true,"description":"Whether the inject-bundle script URL responded successfully. Null when the page has no inject-bundle script tag or its URL could not be resolved."},"cspBlocksWidget":{"type":"boolean","nullable":true,"description":"Whether a Content-Security-Policy detected on the page would block the inject-bundle script host. Null when no CSP is present or the bundle URL is unavailable. True only when the script host is positively absent from the effective script-src or default-src directive."}}},"DiagnosticStartBody":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"The website URL to diagnose","example":"https://myhotel.com"}},"example":{"url":"https://myhotel.com"}},"DiagnosticEvent":{"type":"object","required":["sessionId","runId","type","datetime","url","payload"],"properties":{"sessionId":{"type":"string","description":"Opaque session identifier for the checked site; obtain it from the start-diagnostic response"},"runId":{"type":"string","format":"uuid","description":"Unique run identifier"},"type":{"type":"string","enum":["run_started","progress","finding","run_completed","run_failed","chat_user","chat_assistant"]},"datetime":{"type":"integer","description":"Unix ms timestamp"},"url":{"type":"string","description":"Normalized URL being diagnosed"},"payload":{"type":"object","additionalProperties":true}}},"DiagnosticStartResponse":{"type":"object","required":["sessionId","runId","url","status","channel"],"properties":{"sessionId":{"type":"string"},"runId":{"type":"string","format":"uuid"},"url":{"type":"string"},"status":{"type":"string","enum":["started","already_running"]},"channel":{"type":"string","description":"Real-time events channel path; subscribe to this channel to receive progress and findings as they arrive"}}},"DiagnosticSessionResponse":{"type":"object","required":["sessionId","url","events"],"properties":{"sessionId":{"type":"string"},"url":{"type":"string","nullable":true},"events":{"type":"array","items":{"$ref":"#/components/schemas/DiagnosticEvent"}}}},"DiagnosticChatBody":{"type":"object","required":["message"],"properties":{"message":{"type":"string","minLength":1,"description":"Follow-up chat message","example":"What issues were found with the script placement?"}},"example":{"message":"What issues were found with the script placement?"}},"DiagnosticChatResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Assistant reply"}}},"ScheduleEnum":{"type":"string","enum":["NONE","DAILY","WEEKLY","BI_WEEKLY","MONTHLY"],"description":"Scheduling frequency for analytics or AI visibility runs"},"Client":{"type":"object","required":["id","name","website_id","demo_client","created_date"],"properties":{"id":{"type":"string","format":"uuid","description":"Client UUID"},"name":{"type":"string","description":"Client display name"},"website_id":{"type":"string","format":"uuid","description":"Primary website UUID"},"demo_client":{"type":"boolean","description":"Whether this is a demo client"},"description":{"type":"string","nullable":true,"description":"Optional description of the client"},"scrape_language":{"type":"string","nullable":true,"description":"BCP-47 language code for website scraping (e.g. en, fr)"},"chat_logs_analytics_schedule":{"$ref":"#/components/schemas/ScheduleEnum","description":"Frequency of chat log analytics runs"},"ai_visibility_schedule":{"$ref":"#/components/schemas/ScheduleEnum","description":"Frequency of AI visibility runs"},"last_scraped_date":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp of the most recent website scrape (from linked website)"},"created_date":{"type":"string","format":"date-time","description":"Timestamp when the client was created"},"created_by":{"type":"string","nullable":true,"description":"User ID of the creator"},"disabled_date":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when the client was disabled (null if active)"},"disabled_by":{"type":"string","nullable":true,"description":"User ID who disabled the client"},"_computed":{"type":"object","nullable":true,"description":"Server-computed display fields derived from the client row. Present on single-client responses only.","properties":{"initials":{"type":"string","description":"First two characters of the client name, uppercased (e.g. 'HO'). '?' when name is empty."},"status_label":{"type":"string","enum":["Active","Demo","Disabled"],"description":"Human-readable status. Disabled > Demo > Active precedence."},"status_variant":{"type":"string","enum":["success","warning","danger"],"description":"Badge variant matching status_label."},"website_url":{"type":"string","nullable":true,"description":"Resolved website URL. Null when not available."},"website_hidden":{"type":"boolean","description":"True when website_url is null (hides the website link in the UI)."},"demo_hidden":{"type":"boolean","description":"True when demo_client is false (hides the Demo badge in the UI)."},"is_disabled":{"type":"boolean","description":"True when disabled_date is non-null."},"primary_action_label":{"type":"string","description":"Label for the primary CTA button: 'Enable' when disabled, 'Edit' otherwise."},"disable_label":{"type":"string","description":"Label for the disable toggle action: 'Enable Client' when disabled, 'Disable Client' otherwise."},"created_date_formatted":{"type":"string","description":"created_date formatted for display (e.g. 'Jan 1, 2024')."}},"required":["initials","status_label","status_variant","website_url","website_hidden","demo_hidden","is_disabled","primary_action_label","disable_label","created_date_formatted"]}}},"ClientsSummaryResponse":{"type":"object","required":["totalActive","last90Days"],"properties":{"totalActive":{"type":"integer","description":"Number of active (non-disabled) clients"},"last90Days":{"type":"integer","description":"Number of clients created within the last 90 days (still active)"}}},"ClientMetricsResponse":{"type":"object","required":["clientId","metrics"],"properties":{"clientId":{"type":"string","format":"uuid"},"metrics":{"type":"object","description":"Placeholder for Overview-tab metrics. Empty today; populated in a later release."}}},"RescrapeClientBody":{"type":"object","properties":{"language":{"type":"string","minLength":1,"maxLength":50,"nullable":true,"description":"Optional override for the scrape language (e.g. 'English', 'French'). Defaults to the client's configured scrape_language, then 'English'."}}},"RescrapeClientResponse":{"type":"object","required":["scrapeSessionId","enqueued"],"properties":{"scrapeSessionId":{"type":"string","format":"uuid"},"enqueued":{"type":"boolean","description":"true when the scrape task was accepted for processing; false in environments where task dispatch is not configured — the session is recorded but will not run automatically."}}},"DemoSiteBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Override name used to slugify the preview-site folder."},"website":{"type":"string","format":"uri","description":"Override client website rendered inside the preview iframe. Defaults to the client's configured website."}}},"DemoSiteResponse":{"type":"object","required":["previewUrl","folderName"],"properties":{"previewUrl":{"type":"string","format":"uri"},"folderName":{"type":"string"}}},"ClientListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Client"},"description":"Page of client records"},"total":{"type":"integer","description":"Total number of matching clients (across all pages)"},"limit":{"type":"integer","description":"Page size used for this request"},"nextCursor":{"type":"string","nullable":true,"description":"Opaque cursor for the next page. Null when there are no more pages."},"hasMore":{"type":"boolean","description":"Whether additional pages exist after this one"}}},"CreateClientBody":{"type":"object","required":["name","website_id"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Client name"},"website_id":{"type":"string","format":"uuid","description":"UUID of the primary website"},"demo_client":{"type":"boolean","default":false,"description":"Whether this client is a demo"},"description":{"type":"string","maxLength":1000,"nullable":true,"description":"Optional client description"},"scrape_language":{"type":"string","maxLength":10,"nullable":true,"description":"BCP-47 language code for scraping (e.g. en, fr)"},"chat_logs_analytics_schedule":{"$ref":"#/components/schemas/ScheduleEnum","default":"NONE"},"ai_visibility_schedule":{"$ref":"#/components/schemas/ScheduleEnum","default":"NONE"}}},"UserStatus":{"type":"string","enum":["active","disabled","invited","expired"],"description":"Computed user status derived from disabled_date, accepted_date, and invite_expiry_date"},"UserListItem":{"type":"object","required":["id","email","first_name","last_name","status","created_date"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/UserStatus"},"roles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"client_name":{"type":"string","nullable":true}}}},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}},"api_key_count":{"type":"integer"},"last_login_date":{"type":"string","format":"date-time","nullable":true},"disabled_date":{"type":"string","format":"date-time","nullable":true},"created_date":{"type":"string","format":"date-time"},"invited_by_email":{"type":"string","nullable":true},"invite_expiry_date":{"type":"string","format":"date-time","nullable":true},"accepted_date":{"type":"string","format":"date-time","nullable":true}}},"UserListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/UserListItem"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}},"InviteUserBody":{"type":"object","required":["email","first_name","last_name"],"properties":{"email":{"type":"string","format":"email","maxLength":254},"first_name":{"type":"string","minLength":1,"maxLength":100},"last_name":{"type":"string","minLength":1,"maxLength":100},"role_ids":{"type":"array","items":{"type":"object","properties":{"role_id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid","nullable":true}}}},"group_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"invite_expiry_days":{"type":"integer","minimum":1,"maximum":90,"default":7}}},"UpdateUserBody":{"type":"object","properties":{"first_name":{"type":"string","minLength":1,"maxLength":100},"last_name":{"type":"string","minLength":1,"maxLength":100},"phone":{"type":"string","maxLength":30,"nullable":true},"enable":{"type":"boolean"}}},"InviteUserResponse":{"type":"object","required":["id","email","invite_expiry_date"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"invite_expiry_date":{"type":"string","format":"date-time"}}},"ReinviteUserBody":{"type":"object","properties":{"invite_expiry_days":{"type":"integer","minimum":1,"maximum":90,"default":7}}},"ForceResetResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"ActivityEvent":{"type":"object","required":["event_date","action"],"properties":{"event_date":{"type":"string","format":"date-time","description":"ISO 8601 timestamp of when the event occurred"},"action":{"type":"string","enum":["login","role_assigned","role_removed","group_added","group_removed","api_key_created","api_key_disabled","invited","invite_accepted","disabled"],"description":"Type of activity event"},"actor_email":{"type":"string","nullable":true,"description":"Email of the user who performed the action (null if performed by the user themselves or unknown)"},"detail":{"type":"string","nullable":true,"description":"Additional context (e.g. role name, group name, API key description)"}}},"UserActivityResponse":{"type":"object","required":["items","hasMore","nextCursor"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Page of activity events ordered by event_date DESC"},"hasMore":{"type":"boolean","description":"Whether additional pages exist after this one"},"nextCursor":{"type":"string","nullable":true,"description":"Opaque cursor for the next page. Null when there are no more pages."}}},"RoleListItem":{"type":"object","required":["id","name","description","visibility_maison_only","policy_count","user_count","group_count","created_date"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"client_id":{"type":"string","nullable":true},"client_name":{"type":"string","nullable":true},"visibility_maison_only":{"type":"boolean","nullable":true},"policy_count":{"type":"integer"},"user_count":{"type":"integer"},"group_count":{"type":"integer"},"created_date":{"type":"string","format":"date-time"},"disabled_date":{"type":"string","format":"date-time","nullable":true}}},"RoleDetail":{"type":"object","required":["id","name","description","visibility_maison_only","policy_count","user_count","group_count","created_date","policies"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"client_id":{"type":"string","nullable":true},"client_name":{"type":"string","nullable":true},"visibility_maison_only":{"type":"boolean","nullable":true},"policy_count":{"type":"integer"},"user_count":{"type":"integer"},"group_count":{"type":"integer"},"created_date":{"type":"string","format":"date-time"},"disabled_date":{"type":"string","format":"date-time","nullable":true},"created_by_email":{"type":"string","nullable":true},"disabled_by_email":{"type":"string","nullable":true},"policies":{"type":"array","items":{"type":"object","required":["id","permission","created_date"],"properties":{"id":{"type":"string","format":"uuid"},"feature_id":{"type":"string","nullable":true},"feature_name":{"type":"string","nullable":true},"client_id":{"type":"string","nullable":true},"client_name":{"type":"string","nullable":true},"client_region_id":{"type":"string","nullable":true},"region_name":{"type":"string","nullable":true},"client_department_id":{"type":"string","nullable":true},"department_name":{"type":"string","nullable":true},"tag_id":{"type":"string","nullable":true},"tag_name":{"type":"string","nullable":true},"permission":{"type":"string","enum":["READ","WRITE","EXECUTE","DENY"]},"created_date":{"type":"string","format":"date-time"},"created_by_email":{"type":"string","nullable":true}}}}}},"RoleListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RoleListItem"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}},"CreateRoleBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"client_id":{"type":"string","nullable":true},"visibility_maison_only":{"type":"boolean"}}},"UpdateRoleBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"visibility_maison_only":{"type":"boolean"}}},"AddPolicyBody":{"type":"object","required":["permission"],"properties":{"feature_id":{"type":"string","nullable":true},"client_id":{"type":"string","nullable":true},"client_region_id":{"type":"string","nullable":true},"client_department_id":{"type":"string","nullable":true},"tag_id":{"type":"string","nullable":true},"permission":{"type":"string","enum":["READ","WRITE","EXECUTE","DENY"]}}},"RoleUsersResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","email","assigned_date"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"first_name":{"type":"string"},"last_name":{"type":"string"},"client_id":{"type":"string","nullable":true},"client_name":{"type":"string","nullable":true},"assigned_date":{"type":"string","format":"date-time"},"assigned_by_email":{"type":"string","nullable":true}}}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}},"RoleGroupsResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","assigned_date"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"client_id":{"type":"string","nullable":true},"client_name":{"type":"string","nullable":true},"assigned_date":{"type":"string","format":"date-time"},"assigned_by_email":{"type":"string","nullable":true}}}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}},"UserGroupMemberItem":{"type":"object","required":["user_id","email","first_name","last_name","status","joined_date"],"properties":{"user_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"first_name":{"type":"string"},"last_name":{"type":"string"},"status":{"type":"string","enum":["active","disabled","invited","expired"]},"joined_date":{"type":"string","format":"date-time"},"added_by_email":{"type":"string","nullable":true}}},"UserGroupRoleItem":{"type":"object","required":["role_id","role_name","assigned_date"],"properties":{"role_id":{"type":"string","format":"uuid"},"role_name":{"type":"string"},"client_id":{"type":"string","format":"uuid","nullable":true},"client_name":{"type":"string","nullable":true},"assigned_date":{"type":"string","format":"date-time"},"assigned_by_email":{"type":"string","nullable":true}}},"UserGroupListItem":{"type":"object","required":["id","name","member_count","role_count","created_date"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"client_name":{"type":"string","nullable":true},"member_count":{"type":"integer"},"role_count":{"type":"integer"},"created_date":{"type":"string","format":"date-time"}}},"UserGroupDetail":{"type":"object","required":["id","name","created_date","members","roles","member_count","role_count"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"client_name":{"type":"string","nullable":true},"created_date":{"type":"string","format":"date-time"},"created_by_email":{"type":"string","nullable":true},"deleted_date":{"type":"string","format":"date-time","nullable":true},"members":{"type":"array","items":{"$ref":"#/components/schemas/UserGroupMemberItem"}},"roles":{"type":"array","items":{"$ref":"#/components/schemas/UserGroupRoleItem"}},"member_count":{"type":"integer"},"role_count":{"type":"integer"}}},"UserGroupListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/UserGroupListItem"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}},"CreateUserGroupBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"client_id":{"type":"string","format":"uuid"}}},"UpdateUserGroupBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}},"UpdateGroupMembersBody":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string","format":"uuid"}},"remove":{"type":"array","items":{"type":"string","format":"uuid"}}}},"UpdateGroupRolesBody":{"type":"object","properties":{"add":{"type":"array","items":{"type":"object","required":["role_id"],"properties":{"role_id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"}}}},"remove":{"type":"array","items":{"type":"object","required":["role_id"],"properties":{"role_id":{"type":"string","format":"uuid"},"client_id":{"type":"string","format":"uuid"}}}}}},"UpdateGroupMembersResponse":{"type":"object","required":["added","removed"],"properties":{"added":{"type":"integer"},"removed":{"type":"integer"}}},"UpdateGroupRolesResponse":{"type":"object","required":["added","removed"],"properties":{"added":{"type":"integer"},"removed":{"type":"integer"}}},"FeatureItem":{"type":"object","required":["id","name","description","deprecated"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"deprecated":{"type":"boolean"}}},"FeatureListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FeatureItem"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}},"CreateFeatureBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}},"UpdateFeatureBody":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}},"RegionListItem":{"type":"object","required":["id","name","description","created_date"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"created_date":{"type":"string","format":"date-time"}}},"RegionListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RegionListItem"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}},"CreateRegionBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":1000}}},"UpdateRegionBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":1000}}},"DepartmentListItem":{"type":"object","required":["id","name","description","created_date"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"created_date":{"type":"string","format":"date-time"}}},"DepartmentListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DepartmentListItem"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}},"CreateDepartmentBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":1000}}},"UpdateDepartmentBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":1000}}},"TagListItem":{"type":"object","required":["id","name","description","created_date"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"created_date":{"type":"string","format":"date-time"}}},"TagListResponse":{"type":"object","required":["items","total","limit","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/TagListItem"}},"total":{"type":"integer"},"limit":{"type":"integer"},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}},"CreateTagBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":1000}}},"UpdateTagBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":1000}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}},"AgentCard":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"version":{"type":"string"},"capabilities":{"type":"object","properties":{"streaming":{"type":"boolean"},"pushNotifications":{"type":"boolean"}}},"authentication":{"type":"object","properties":{"schemes":{"type":"array","items":{"type":"string"}},"credentials":{"type":"string"}}},"defaultInputModes":{"type":"array","items":{"type":"string"}},"defaultOutputModes":{"type":"array","items":{"type":"string"}},"skills":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}}}}}},"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"HMAC-signed API key"},"sessionAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Maison session token (cookie or Authorization: Bearer header)"}}}}