{ "openapi": "3.1.0", "info": { "title": "Clawbolt", "version": "0.1.0" }, "paths": { "/api/health": { "get": { "summary": "Health Check", "description": "Full health check: process is up AND can reach the database.\n\nUse for ops dashboards and richer monitoring. NOT recommended as the\ndeployment platform's healthcheck path: during an incident a\nhealthcheck that waits on the same DB can pile up alongside whatever\nalready broke. Use ``/health/live`` for that.", "operationId": "health_check_api_health_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } } } } } }, "/api/health/live": { "get": { "summary": "Health Live", "description": "Liveness probe: the process is up and the event loop is responsive.\n\nNo DB hit, no external calls. Returns instantly when the worker can\nprocess requests. Designed for the deployment platform's healthcheck\nso a stuck DB / external dep / slow query does not also block the\nhealthcheck and prevent traffic from rolling to a fresh container.\nUse ``/health`` for the deeper \"is the system actually working\" check.", "operationId": "health_live_api_health_live_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } } } } } }, "/api/app/config": { "get": { "summary": "App Config", "operationId": "app_config_api_app_config_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppConfigResponse" } } } } } } }, "/api/auth/config": { "get": { "summary": "Auth Config", "operationId": "auth_config_api_auth_config_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "additionalProperties": true, "type": "object", "title": "Response Auth Config Api Auth Config Get" } } } } } } }, "/api/oauth/status": { "get": { "summary": "Get Oauth Status", "description": "Return connection status for all OAuth integrations.", "operationId": "get_oauth_status_api_oauth_status_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthStatusResponse" } } } } } } }, "/api/oauth/{integration}/authorize": { "get": { "summary": "Get Authorize Url", "description": "Generate an authorization URL for the given integration.", "operationId": "get_authorize_url_api_oauth__integration__authorize_get", "parameters": [ { "name": "integration", "in": "path", "required": true, "schema": { "type": "string", "title": "Integration" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthAuthorizeResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/oauth/callback": { "get": { "summary": "Oauth Callback", "description": "Handle OAuth provider redirect after user authorization.\n\nThe provider redirects here with an authorization code and the state\nparameter we generated earlier. We exchange the code for tokens,\npersist them, and redirect the user to the frontend success page.\n\nAll parameters are optional because OAuth providers may redirect with\nonly error parameters (no code/state) when the user denies access.\n\nWhen the flow was initiated from chat (source=\"chat\"), a standalone\nHTML page is returned instead of redirecting to the SPA, so users\non SMS/iMessage see a \"you can close this tab\" message.", "operationId": "oauth_callback_api_oauth_callback_get", "parameters": [ { "name": "code", "in": "query", "required": false, "schema": { "type": "string", "default": "", "title": "Code" } }, { "name": "state", "in": "query", "required": false, "schema": { "type": "string", "default": "", "title": "State" } }, { "name": "realmId", "in": "query", "required": false, "schema": { "type": "string", "default": "", "title": "Realmid" } }, { "name": "error", "in": "query", "required": false, "schema": { "type": "string", "default": "", "title": "Error" } }, { "name": "error_description", "in": "query", "required": false, "schema": { "type": "string", "default": "", "title": "Error Description" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/oauth/{integration}": { "delete": { "summary": "Disconnect Integration", "description": "Disconnect an OAuth integration by removing stored tokens.", "operationId": "disconnect_integration_api_oauth__integration__delete", "parameters": [ { "name": "integration", "in": "path", "required": true, "schema": { "type": "string", "title": "Integration" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Disconnect Integration Api Oauth Integration Delete" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/integrations/servicetitan/connect": { "post": { "summary": "Connect Servicetitan", "description": "Validate ServiceTitan client credentials and persist them.", "operationId": "connect_servicetitan_api_integrations_servicetitan_connect_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ServiceTitanConnectRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/integrations/servicetitan": { "delete": { "summary": "Disconnect Servicetitan", "description": "Remove the user's stored ServiceTitan credential.", "operationId": "disconnect_servicetitan_api_integrations_servicetitan_delete", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionResponse" } } } } } } }, "/api/integrations/appfolio_vendor/connect": { "post": { "summary": "Connect Appfolio", "description": "Exchange a pasted AppFolio magic link for a credential and persist it.", "operationId": "connect_appfolio_api_integrations_appfolio_vendor_connect_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppFolioConnectRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/integrations/appfolio_vendor": { "delete": { "summary": "Disconnect Appfolio", "description": "Remove the user's stored AppFolio credential.", "operationId": "disconnect_appfolio_api_integrations_appfolio_vendor_delete", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionResponse" } } } } } } }, "/api/media/temp/{token}": { "get": { "summary": "Serve Temp Media", "description": "Serve a temporarily staged media file. No auth required.\n\nThe token stays valid for the full TTL (5 minutes) and can be\nfetched multiple times. External services like CompanyCam may\ndownload the image more than once (original + thumbnails).", "operationId": "serve_temp_media_api_media_temp__token__get", "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string", "title": "Token" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/webhooks/telegram": { "post": { "summary": "Telegram Inbound", "description": "Receive inbound messages from Telegram.", "operationId": "telegram_inbound_api_webhooks_telegram_post", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/api/user/chat": { "post": { "tags": [ "webchat" ], "summary": "Send Chat Message", "description": "Accept a message, publish to bus, return request_id for SSE.", "operationId": "send_chat_message_api_user_chat_post", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_send_chat_message_api_user_chat_post" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/_ChatAccepted" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/chat/events/{request_id}": { "get": { "tags": [ "webchat" ], "summary": "Chat Events", "description": "SSE endpoint: streams tool-call events then the final reply.", "operationId": "chat_events_api_user_chat_events__request_id__get", "parameters": [ { "name": "request_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Request Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/chat/activity": { "get": { "tags": [ "webchat" ], "summary": "Chat Activity", "description": "SSE endpoint: streams agent activity (thinking, tool use) for this user.\n\nDelivers real-time status regardless of which channel (Telegram,\nwebchat, etc.) originated the message being processed. Multiple\nbrowser tabs can subscribe concurrently.", "operationId": "chat_activity_api_user_chat_activity_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/api/webhooks/linq": { "post": { "summary": "Linq Inbound", "description": "Receive inbound messages from Linq.", "operationId": "linq_inbound_api_webhooks_linq_post", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/api/webhooks/bluebubbles": { "post": { "summary": "Bluebubbles Inbound", "description": "Receive inbound messages from BlueBubbles.", "operationId": "bluebubbles_inbound_api_webhooks_bluebubbles_post", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/api/webhooks/twilio": { "post": { "summary": "Twilio Inbound", "description": "Receive inbound SMS/MMS from Twilio.\n\nReturns an empty TwiML response immediately; the agent loop\nreplies through the outbound dispatcher via the REST API so\nthis endpoint stays under Twilio's 15s ack window even when\nthe LLM call takes longer.", "operationId": "twilio_inbound_api_webhooks_twilio_post", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/api/user/profile": { "get": { "summary": "Get Profile", "description": "Return the current user's profile.", "operationId": "get_profile_api_user_profile_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserProfileResponse" } } } } } }, "put": { "summary": "Update Profile", "description": "Partial update of the current user's profile.\n\nBounded-growth columns (``user_text``, ``soul_text``,\n``heartbeat_text``) are routed through\n:func:`backend.app.agent.markdown_registry.assert_column_within_budget`\nso the dashboard editor cannot bypass the byte cap that the agent's\nworkspace tools and compaction paths already respect. Returns\n``413 Payload Too Large`` with the registry's actual / allowed\nsizes so a client-side editor can show a useful error.", "operationId": "update_profile_api_user_profile_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserProfileUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserProfileResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/data-sharing-consent": { "get": { "summary": "Get Data Sharing Consent", "description": "Return the current user's data sharing consent state.", "operationId": "get_data_sharing_consent_api_user_data_sharing_consent_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DataSharingConsentResponse" } } } } } }, "put": { "summary": "Update Data Sharing Consent", "description": "Toggle the current user's data sharing consent.\n\nStamps ``data_sharing_consent_at`` with the current UTC time on every\ncall, regardless of whether the value changed. This makes the column\na \"last toggled at\" timestamp rather than a \"first opted in at\" one,\nwhich is the cheaper guarantee to keep correct: a one-shot accidental\ndouble-PUT can't drift the timestamp.", "operationId": "update_data_sharing_consent_api_user_data_sharing_consent_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DataSharingConsentRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DataSharingConsentResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/channels/config": { "get": { "summary": "Get Channel Config", "description": "Return server-level channel configuration.", "operationId": "get_channel_config_api_user_channels_config_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChannelConfigResponse" } } } } } }, "put": { "summary": "Update Channel Config", "description": "Update server-level channel configuration.", "operationId": "update_channel_config_api_user_channels_config_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChannelConfigUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChannelConfigResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/channels/routes": { "get": { "summary": "Get Channel Routes", "description": "Return the current user's channel routes with enabled status.", "operationId": "get_channel_routes_api_user_channels_routes_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChannelRouteListResponse" } } } } } } }, "/api/user/channels/routes/{channel}": { "patch": { "summary": "Update Channel Route", "description": "Toggle enabled status for a channel route.\n\nSingle-channel enforcement: when enabling a channel, all other\nnon-webchat routes for this user are automatically disabled so\nexactly one messaging channel is active at a time.\n\nIf the user has no route and no known identifier for this channel yet\n(fresh onboarding), the selection is persisted via ``preferred_channel``\nonly. The route row is created later when the identifier arrives,\neither via an inbound message (OSS) or via an explicit link call\n(premium). This keeps placeholder rows out of the database and avoids\nleaking the user's internal UUID into identifier-shaped UI fields.", "operationId": "update_channel_route_api_user_channels_routes__channel__patch", "parameters": [ { "name": "channel", "in": "path", "required": true, "schema": { "type": "string", "title": "Channel" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChannelRouteUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChannelRouteResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/channels/telegram/bot-info": { "get": { "summary": "Get Telegram Bot Info", "description": "Return the Telegram bot username, auto-discovered via getMe.", "operationId": "get_telegram_bot_info_api_channels_telegram_bot_info_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TelegramBotInfoResponse" } } } } } } }, "/api/user/model/config": { "get": { "summary": "Get Model Config", "description": "Return server-level LLM model configuration.", "operationId": "get_model_config_api_user_model_config_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelConfigResponse" } } } } } }, "put": { "summary": "Update Model Config", "description": "Update server-level LLM model configuration.\n\nNOTE: In single-tenant (OSS) mode, all authenticated users are\neffectively admins and can modify these settings. The premium layer\nadds role-based guards via AdminConfigGuardMiddleware to restrict\nthis to admin users only.", "operationId": "update_model_config_api_user_model_config_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelConfigUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelConfigResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/providers": { "get": { "summary": "List Providers", "description": "List available LLM providers from any-llm.", "operationId": "list_providers_api_user_providers_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ProviderInfo" }, "type": "array", "title": "Response List Providers Api User Providers Get" } } } } } } }, "/api/user/providers/{provider}/models": { "get": { "summary": "List Provider Models", "description": "List available models for a provider.", "operationId": "list_provider_models_api_user_providers__provider__models_get", "parameters": [ { "name": "provider", "in": "path", "required": true, "schema": { "type": "string", "title": "Provider" } }, { "name": "api_base", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Base" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "string" }, "title": "Response List Provider Models Api User Providers Provider Models Get" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/heartbeat-logs": { "get": { "summary": "Get Heartbeat Logs", "description": "List heartbeat logs for the current user, most recent first.", "operationId": "get_heartbeat_logs_api_user_heartbeat_logs_get", "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 200, "minimum": 1, "default": 50, "title": "Limit" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HeartbeatLogListResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "summary": "Delete Heartbeat Logs", "description": "Delete all heartbeat logs for the current user.", "operationId": "delete_heartbeat_logs_api_user_heartbeat_logs_delete", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteHeartbeatLogsResponse" } } } } } } }, "/api/user/llm-usage": { "get": { "summary": "Get Llm Usage", "description": "Aggregate LLM usage for the current user over the last N days.", "operationId": "get_llm_usage_api_user_llm_usage_get", "parameters": [ { "name": "days", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 365, "minimum": 1, "default": 30, "title": "Days" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LLMUsageSummary" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/conversation": { "get": { "summary": "Get Conversation", "description": "Return the user's conversation transcript, or an empty shape if none yet.\n\nReturning an empty shape (rather than 404) lets the frontend render\nthe chat input without special-casing the first-message-ever flow.\nThe session row is created by the agent pipeline on the first\ninbound message, not by this endpoint.", "operationId": "get_conversation_api_user_conversation_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionDetailResponse" } } } } } } }, "/api/user/conversation/system-prompt": { "get": { "summary": "Get Conversation System Prompt", "description": "Return the system prompt that would be sent on the next turn.\n\nReconstructed live from current user state (profile, soul, memory,\nonboarding status, tool availability) so the UI doesn't show a\nstale snapshot from the first turn of the session.\n\nKnown approximations:\n\n* The preview omits specialist tool guidelines that get appended\n mid-turn when the LLM calls ``list_capabilities`` to activate a\n category. It matches the start-of-turn tool list, mirroring how\n the agent itself starts each turn fresh.\n* Tools whose factories require a storage backend or an outbound\n publish hook (currently ``send_media_reply``,\n ``upload_to_storage``, and ``move_file``) are filtered out\n by the registry's dependency gates because the preview can't\n safely construct those runtime hooks. Their usage hints will\n not appear in the Tool Guidelines section.\n* If a user's ``BOOTSTRAP.md`` cannot be created on disk by the\n runtime (rare, requires an OS-level error), the runtime drops\n out of onboarding mode while this preview still reports\n ``is_onboarding=true`` based on the in-memory heuristic.", "operationId": "get_conversation_system_prompt_api_user_conversation_system_prompt_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionSystemPromptResponse" } } } } } } }, "/api/user/conversation/messages/batch": { "delete": { "summary": "Delete Messages Batch", "description": "Delete specific messages from the user's conversation by sequence number.", "operationId": "delete_messages_batch_api_user_conversation_messages_batch_delete", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchDeleteRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteMessagesResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/conversation/messages/{seq}": { "delete": { "summary": "Delete Single Message", "description": "Delete a single message from the user's conversation by sequence number.", "operationId": "delete_single_message_api_user_conversation_messages__seq__delete", "parameters": [ { "name": "seq", "in": "path", "required": true, "schema": { "type": "integer", "title": "Seq" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteMessageResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/conversation/messages": { "delete": { "summary": "Delete Conversation History", "description": "Delete all messages from the user's conversation, preserving memory.\n\nResets the initial system prompt so the conversation continues with\na clean slate while retaining compacted memory.", "operationId": "delete_conversation_history_api_user_conversation_messages_delete", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteMessagesResponse" } } } } } } }, "/api/user/memory": { "get": { "summary": "Get Memory", "description": "Return the raw MEMORY.md content.", "operationId": "get_memory_api_user_memory_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemoryResponse" } } } } } }, "put": { "summary": "Update Memory", "description": "Overwrite MEMORY.md with new content.\n\nReturns ``413 Payload Too Large`` when *body.content* exceeds the\nbounded-growth byte budget for ``MEMORY.md`` (see\n:mod:`backend.app.agent.markdown_registry`). The original message\nfrom the registry includes the actual size and the budget so a\nuser-side editor can show a useful error.", "operationId": "update_memory_api_user_memory_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemoryUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemoryResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/permissions": { "get": { "summary": "Get Permissions", "description": "Return the current PERMISSIONS.json content.", "operationId": "get_permissions_api_user_permissions_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PermissionsResponse" } } } } } }, "put": { "summary": "Update Permissions", "description": "Overwrite PERMISSIONS.json with new content.", "operationId": "update_permissions_api_user_permissions_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PermissionsUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PermissionsResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/tools": { "get": { "summary": "Get Tool Config", "description": "Return the current tool configuration for the user.", "operationId": "get_tool_config_api_user_tools_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToolConfigResponse" } } } } } }, "put": { "summary": "Update Tool Config", "description": "Update tool configuration for the user.\n\nOnly factories that are not ``dashboard_always_enabled`` can be\ntoggled at the factory level. Attempts to disable always-enabled\ntools are silently ignored.\n\nEach entry may include a ``sub_tools`` list with explicit\n``permission_level`` values to override individual sub-tools. Levels\nare persisted to ``user_permissions``; ``\"never\"`` filters the\nsub-tool out of the LLM schema on the next turn.", "operationId": "update_tool_config_api_user_tools_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToolConfigUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToolConfigResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/calendar/calendars": { "get": { "summary": "List Calendars", "description": "Fetch the user's Google Calendar list from the Google API.", "operationId": "list_calendars_api_user_calendar_calendars_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CalendarListResponse" } } } } } } }, "/api/user/calendar/config": { "get": { "summary": "Get Calendar Config", "description": "Get all enabled calendars for the user.", "operationId": "get_calendar_config_api_user_calendar_config_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CalendarConfigResponse" } } } } } }, "put": { "summary": "Update Calendar Config", "description": "Replace all enabled calendars (delete existing, insert new).\n\nThe ``is_primary`` flag is auto-detected by querying Google's\ncalendarList for the current user, so the frontend does not need to\npass it through. The agent uses it to disambiguate when the LLM\nomits ``calendar_id`` and the user has multiple enabled calendars.", "operationId": "update_calendar_config_api_user_calendar_config_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CalendarConfigUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CalendarConfigResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } } }, "components": { "schemas": { "AppConfigResponse": { "properties": { "chat_web_attachments_enabled": { "type": "boolean", "title": "Chat Web Attachments Enabled" } }, "type": "object", "required": [ "chat_web_attachments_enabled" ], "title": "AppConfigResponse", "description": "Deployment-level feature flags the frontend reads on app load." }, "AppFolioConnectRequest": { "properties": { "magic_link": { "type": "string", "minLength": 1, "format": "password", "title": "Magic Link", "writeOnly": true } }, "type": "object", "required": [ "magic_link" ], "title": "AppFolioConnectRequest", "description": "A pasted AppFolio magic link (full URL or the bare token).\n\n``magic_link`` is a single-use secret, so it is a ``SecretStr`` (masked\nin logs/reprs, write-only in the OpenAPI schema)." }, "BatchDeleteRequest": { "properties": { "seqs": { "items": { "type": "integer" }, "type": "array", "maxItems": 1000, "minItems": 1, "title": "Seqs" } }, "type": "object", "required": [ "seqs" ], "title": "BatchDeleteRequest" }, "Body_send_chat_message_api_user_chat_post": { "properties": { "message": { "type": "string", "title": "Message", "default": "" }, "files": { "items": { "type": "string", "contentMediaType": "application/octet-stream" }, "type": "array", "title": "Files", "default": [] } }, "type": "object", "title": "Body_send_chat_message_api_user_chat_post" }, "CalendarConfigEntry": { "properties": { "calendar_id": { "type": "string", "title": "Calendar Id" }, "display_name": { "type": "string", "title": "Display Name" }, "disabled_tools": { "items": { "type": "string" }, "type": "array", "title": "Disabled Tools" }, "access_role": { "type": "string", "title": "Access Role", "default": "" } }, "type": "object", "required": [ "calendar_id", "display_name" ], "title": "CalendarConfigEntry" }, "CalendarConfigResponse": { "properties": { "calendars": { "items": { "$ref": "#/components/schemas/CalendarConfigEntry" }, "type": "array", "title": "Calendars" } }, "type": "object", "required": [ "calendars" ], "title": "CalendarConfigResponse" }, "CalendarConfigUpdate": { "properties": { "calendars": { "items": { "$ref": "#/components/schemas/CalendarConfigEntry" }, "type": "array", "title": "Calendars" } }, "type": "object", "required": [ "calendars" ], "title": "CalendarConfigUpdate" }, "CalendarListEntry": { "properties": { "id": { "type": "string", "title": "Id" }, "summary": { "type": "string", "title": "Summary" }, "primary": { "type": "boolean", "title": "Primary", "default": false }, "access_role": { "type": "string", "title": "Access Role", "default": "" } }, "type": "object", "required": [ "id", "summary" ], "title": "CalendarListEntry" }, "CalendarListResponse": { "properties": { "calendars": { "items": { "$ref": "#/components/schemas/CalendarListEntry" }, "type": "array", "title": "Calendars" } }, "type": "object", "required": [ "calendars" ], "title": "CalendarListResponse" }, "ChannelConfigResponse": { "properties": { "telegram_bot_token_set": { "type": "boolean", "title": "Telegram Bot Token Set" }, "telegram_allowed_chat_id": { "type": "string", "title": "Telegram Allowed Chat Id" }, "linq_api_token_set": { "type": "boolean", "title": "Linq Api Token Set", "default": false }, "linq_from_number": { "type": "string", "title": "Linq From Number", "default": "" }, "linq_allowed_numbers": { "type": "string", "title": "Linq Allowed Numbers", "default": "" }, "linq_preferred_service": { "type": "string", "title": "Linq Preferred Service", "default": "iMessage" }, "bluebubbles_configured": { "type": "boolean", "title": "Bluebubbles Configured", "default": false }, "bluebubbles_allowed_numbers": { "type": "string", "title": "Bluebubbles Allowed Numbers", "default": "" }, "bluebubbles_imessage_address": { "type": "string", "title": "Bluebubbles Imessage Address", "default": "" }, "imessage_backend": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Imessage Backend" }, "twilio_configured": { "type": "boolean", "title": "Twilio Configured", "default": false }, "twilio_phone_number": { "type": "string", "title": "Twilio Phone Number", "default": "" }, "twilio_messaging_service_sid": { "type": "string", "title": "Twilio Messaging Service Sid", "default": "" }, "twilio_allowed_numbers": { "type": "string", "title": "Twilio Allowed Numbers", "default": "" } }, "type": "object", "required": [ "telegram_bot_token_set", "telegram_allowed_chat_id" ], "title": "ChannelConfigResponse" }, "ChannelConfigUpdate": { "properties": { "telegram_bot_token": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Telegram Bot Token" }, "telegram_allowed_chat_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Telegram Allowed Chat Id" }, "linq_api_token": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Linq Api Token" }, "linq_from_number": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Linq From Number" }, "linq_webhook_signing_secret": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Linq Webhook Signing Secret" }, "linq_allowed_numbers": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Linq Allowed Numbers" }, "linq_preferred_service": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Linq Preferred Service" }, "bluebubbles_server_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Bluebubbles Server Url" }, "bluebubbles_password": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Bluebubbles Password" }, "bluebubbles_allowed_numbers": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Bluebubbles Allowed Numbers" }, "bluebubbles_imessage_address": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Bluebubbles Imessage Address" }, "twilio_account_sid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Twilio Account Sid" }, "twilio_auth_token": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Twilio Auth Token" }, "twilio_api_key_sid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Twilio Api Key Sid" }, "twilio_api_key_secret": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Twilio Api Key Secret" }, "twilio_phone_number": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Twilio Phone Number" }, "twilio_messaging_service_sid": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Twilio Messaging Service Sid" }, "twilio_allowed_numbers": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Twilio Allowed Numbers" } }, "type": "object", "title": "ChannelConfigUpdate" }, "ChannelRouteListResponse": { "properties": { "routes": { "items": { "$ref": "#/components/schemas/ChannelRouteResponse" }, "type": "array", "title": "Routes" } }, "type": "object", "required": [ "routes" ], "title": "ChannelRouteListResponse" }, "ChannelRouteResponse": { "properties": { "channel": { "type": "string", "title": "Channel" }, "channel_identifier": { "type": "string", "title": "Channel Identifier" }, "enabled": { "type": "boolean", "title": "Enabled" }, "created_at": { "type": "string", "title": "Created At" }, "last_inbound_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last Inbound At" } }, "type": "object", "required": [ "channel", "channel_identifier", "enabled", "created_at" ], "title": "ChannelRouteResponse" }, "ChannelRouteUpdate": { "properties": { "enabled": { "type": "boolean", "title": "Enabled" } }, "type": "object", "required": [ "enabled" ], "title": "ChannelRouteUpdate" }, "DataSharingConsentRequest": { "properties": { "consent": { "type": "boolean", "title": "Consent" } }, "type": "object", "required": [ "consent" ], "title": "DataSharingConsentRequest", "description": "Body for ``PUT /api/user/data-sharing-consent``.\n\nSingle boolean. The endpoint always stamps ``data_sharing_consent_at``\nwith ``now()`` regardless of whether ``consent`` is ``True`` or\n``False``, so consent toggle history can be reconstructed even when\nno separate audit table exists." }, "DataSharingConsentResponse": { "properties": { "data_sharing_consent": { "type": "boolean", "title": "Data Sharing Consent" }, "data_sharing_consent_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Data Sharing Consent At" } }, "type": "object", "required": [ "data_sharing_consent", "data_sharing_consent_at" ], "title": "DataSharingConsentResponse", "description": "Returned by the consent setter and getter.\n\n``data_sharing_consent_at`` is the timestamp of the last toggle,\nnot \"first opted in.\" If a user opts in, then opts out, this column\nholds the opt-out time." }, "DeleteHeartbeatLogsResponse": { "properties": { "status": { "type": "string", "title": "Status" }, "deleted": { "type": "integer", "title": "Deleted" } }, "type": "object", "required": [ "status", "deleted" ], "title": "DeleteHeartbeatLogsResponse" }, "DeleteMessageResponse": { "properties": { "status": { "type": "string", "title": "Status" }, "seq": { "type": "integer", "title": "Seq" } }, "type": "object", "required": [ "status", "seq" ], "title": "DeleteMessageResponse" }, "DeleteMessagesResponse": { "properties": { "status": { "type": "string", "title": "Status" }, "messages_deleted": { "type": "integer", "title": "Messages Deleted" } }, "type": "object", "required": [ "status", "messages_deleted" ], "title": "DeleteMessagesResponse" }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "type": "array", "title": "Detail" } }, "type": "object", "title": "HTTPValidationError" }, "HealthResponse": { "properties": { "status": { "type": "string", "title": "Status" }, "database": { "type": "string", "title": "Database", "default": "ok" } }, "type": "object", "required": [ "status" ], "title": "HealthResponse" }, "HeartbeatLogItemResponse": { "properties": { "id": { "type": "integer", "title": "Id" }, "user_id": { "type": "string", "title": "User Id" }, "action_type": { "type": "string", "title": "Action Type", "default": "send" }, "message_text": { "type": "string", "title": "Message Text", "default": "" }, "channel": { "type": "string", "title": "Channel", "default": "" }, "reasoning": { "type": "string", "title": "Reasoning", "default": "" }, "tasks": { "type": "string", "title": "Tasks", "default": "" }, "created_at": { "type": "string", "title": "Created At" } }, "type": "object", "required": [ "id", "user_id", "created_at" ], "title": "HeartbeatLogItemResponse" }, "HeartbeatLogListResponse": { "properties": { "total": { "type": "integer", "title": "Total" }, "items": { "items": { "$ref": "#/components/schemas/HeartbeatLogItemResponse" }, "type": "array", "title": "Items" } }, "type": "object", "required": [ "total", "items" ], "title": "HeartbeatLogListResponse" }, "IntegrationConnectionResponse": { "properties": { "integration": { "type": "string", "title": "Integration" }, "connected": { "type": "boolean", "title": "Connected" } }, "type": "object", "required": [ "integration", "connected" ], "title": "IntegrationConnectionResponse", "description": "Result of a connect/disconnect on a web-form integration." }, "LLMUsageByPurpose": { "properties": { "purpose": { "type": "string", "title": "Purpose" }, "call_count": { "type": "integer", "title": "Call Count" }, "total_input_tokens": { "type": "integer", "title": "Total Input Tokens" }, "total_output_tokens": { "type": "integer", "title": "Total Output Tokens" }, "total_tokens": { "type": "integer", "title": "Total Tokens" }, "total_cost": { "type": "number", "title": "Total Cost" } }, "type": "object", "required": [ "purpose", "call_count", "total_input_tokens", "total_output_tokens", "total_tokens", "total_cost" ], "title": "LLMUsageByPurpose" }, "LLMUsageSummary": { "properties": { "total_calls": { "type": "integer", "title": "Total Calls" }, "total_tokens": { "type": "integer", "title": "Total Tokens" }, "total_cost": { "type": "number", "title": "Total Cost" }, "by_purpose": { "items": { "$ref": "#/components/schemas/LLMUsageByPurpose" }, "type": "array", "title": "By Purpose" } }, "type": "object", "required": [ "total_calls", "total_tokens", "total_cost", "by_purpose" ], "title": "LLMUsageSummary" }, "MemoryResponse": { "properties": { "content": { "type": "string", "title": "Content" } }, "type": "object", "required": [ "content" ], "title": "MemoryResponse" }, "MemoryUpdate": { "properties": { "content": { "type": "string", "title": "Content" } }, "type": "object", "required": [ "content" ], "title": "MemoryUpdate" }, "ModelConfigResponse": { "properties": { "llm_provider": { "type": "string", "title": "Llm Provider" }, "llm_model": { "type": "string", "title": "Llm Model" }, "llm_api_base": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Api Base" }, "vision_model": { "type": "string", "title": "Vision Model" }, "vision_provider": { "type": "string", "title": "Vision Provider" }, "heartbeat_model": { "type": "string", "title": "Heartbeat Model" }, "heartbeat_provider": { "type": "string", "title": "Heartbeat Provider" }, "compaction_model": { "type": "string", "title": "Compaction Model" }, "compaction_provider": { "type": "string", "title": "Compaction Provider" }, "reasoning_effort": { "type": "string", "title": "Reasoning Effort" } }, "type": "object", "required": [ "llm_provider", "llm_model", "llm_api_base", "vision_model", "vision_provider", "heartbeat_model", "heartbeat_provider", "compaction_model", "compaction_provider", "reasoning_effort" ], "title": "ModelConfigResponse" }, "ModelConfigUpdate": { "properties": { "llm_provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Provider" }, "llm_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Model" }, "llm_api_base": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Api Base" }, "vision_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Vision Model" }, "vision_provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Vision Provider" }, "heartbeat_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Heartbeat Model" }, "heartbeat_provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Heartbeat Provider" }, "compaction_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Compaction Model" }, "compaction_provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Compaction Provider" }, "reasoning_effort": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Reasoning Effort" } }, "type": "object", "title": "ModelConfigUpdate" }, "OAuthAuthorizeResponse": { "properties": { "url": { "type": "string", "title": "Url" }, "integration": { "type": "string", "title": "Integration" } }, "type": "object", "required": [ "url", "integration" ], "title": "OAuthAuthorizeResponse" }, "OAuthStatusEntry": { "properties": { "integration": { "type": "string", "title": "Integration" }, "configured": { "type": "boolean", "title": "Configured" }, "connected": { "type": "boolean", "title": "Connected" } }, "type": "object", "required": [ "integration", "configured", "connected" ], "title": "OAuthStatusEntry" }, "OAuthStatusResponse": { "properties": { "integrations": { "items": { "$ref": "#/components/schemas/OAuthStatusEntry" }, "type": "array", "title": "Integrations" } }, "type": "object", "required": [ "integrations" ], "title": "OAuthStatusResponse" }, "PermissionsResponse": { "properties": { "content": { "type": "string", "title": "Content" } }, "type": "object", "required": [ "content" ], "title": "PermissionsResponse" }, "PermissionsUpdate": { "properties": { "content": { "type": "string", "title": "Content" } }, "type": "object", "required": [ "content" ], "title": "PermissionsUpdate" }, "ProviderInfo": { "properties": { "name": { "type": "string", "title": "Name" }, "local": { "type": "boolean", "title": "Local" } }, "type": "object", "required": [ "name", "local" ], "title": "ProviderInfo" }, "ServiceTitanConnectRequest": { "properties": { "tenant_id": { "type": "string", "minLength": 1, "title": "Tenant Id" }, "client_id": { "type": "string", "minLength": 1, "title": "Client Id" }, "client_secret": { "type": "string", "minLength": 1, "format": "password", "title": "Client Secret", "writeOnly": true } }, "type": "object", "required": [ "tenant_id", "client_id", "client_secret" ], "title": "ServiceTitanConnectRequest", "description": "The three values from ServiceTitan's API Application Access page.\n\n``client_secret`` is a ``SecretStr`` so it is masked in logs/reprs and\nmarked write-only in the OpenAPI schema; the value still arrives as a\nplain JSON string from the client." }, "SessionDetailResponse": { "properties": { "session_id": { "type": "string", "title": "Session Id" }, "user_id": { "type": "string", "title": "User Id" }, "created_at": { "type": "string", "title": "Created At" }, "last_message_at": { "type": "string", "title": "Last Message At" }, "channel": { "type": "string", "title": "Channel", "default": "" }, "messages": { "items": { "$ref": "#/components/schemas/SessionMessage" }, "type": "array", "title": "Messages" } }, "type": "object", "required": [ "session_id", "user_id", "created_at", "last_message_at", "messages" ], "title": "SessionDetailResponse" }, "SessionMessage": { "properties": { "seq": { "type": "integer", "title": "Seq" }, "direction": { "type": "string", "title": "Direction" }, "body": { "type": "string", "title": "Body", "default": "" }, "timestamp": { "type": "string", "title": "Timestamp" }, "tool_interactions": { "items": { "additionalProperties": true, "type": "object" }, "type": "array", "title": "Tool Interactions" } }, "type": "object", "required": [ "seq", "direction", "timestamp" ], "title": "SessionMessage" }, "SessionSystemPromptResponse": { "properties": { "session_id": { "type": "string", "title": "Session Id" }, "system_prompt": { "type": "string", "title": "System Prompt" }, "is_onboarding": { "type": "boolean", "title": "Is Onboarding" } }, "type": "object", "required": [ "session_id", "system_prompt", "is_onboarding" ], "title": "SessionSystemPromptResponse", "description": "Live system prompt that would be sent to the LLM on the next turn.\n\nReconstructed on demand from current user state (memory, profile,\nonboarding status, available tools). The historical first-turn\nsnapshot lives on the ``ChatSession.initial_system_prompt`` column\nfor forensics but is intentionally not exposed via the public API,\nsince it reveals the operator's preamble and tool wiring. Premium\ndeployments additionally gate this endpoint behind an admin guard." }, "SubToolEntryResponse": { "properties": { "name": { "type": "string", "title": "Name" }, "description": { "type": "string", "title": "Description" }, "permission_level": { "type": "string", "title": "Permission Level", "default": "always" }, "hidden_in_permissions": { "type": "boolean", "title": "Hidden In Permissions", "default": false } }, "type": "object", "required": [ "name", "description" ], "title": "SubToolEntryResponse" }, "SubToolPermissionUpdate": { "properties": { "name": { "type": "string", "title": "Name" }, "permission_level": { "type": "string", "title": "Permission Level" } }, "type": "object", "required": [ "name", "permission_level" ], "title": "SubToolPermissionUpdate", "description": "Per-sub-tool permission override sent by the Settings UI.\n\n``permission_level`` is the new value: ``\"always\"`` (auto-run),\n``\"ask\"`` (prompt before running), or ``\"never\"`` (hide from the\nLLM schema). Sub-tools omitted from the update list keep their\ncurrent stored level." }, "TelegramBotInfoResponse": { "properties": { "bot_username": { "type": "string", "title": "Bot Username" }, "bot_link": { "type": "string", "title": "Bot Link" } }, "type": "object", "required": [ "bot_username", "bot_link" ], "title": "TelegramBotInfoResponse" }, "ToolConfigEntryResponse": { "properties": { "name": { "type": "string", "title": "Name" }, "description": { "type": "string", "title": "Description" }, "category": { "type": "string", "title": "Category" }, "domain_group": { "type": "string", "title": "Domain Group", "default": "" }, "domain_group_order": { "type": "integer", "title": "Domain Group Order", "default": 0 }, "enabled": { "type": "boolean", "title": "Enabled" }, "configured": { "type": "boolean", "title": "Configured", "default": true }, "auth_message": { "type": "string", "title": "Auth Message", "default": "" }, "oauth_name": { "type": "string", "title": "Oauth Name", "default": "" }, "always_enabled": { "type": "boolean", "title": "Always Enabled", "default": false }, "connect_form": { "type": "string", "title": "Connect Form", "default": "" }, "sub_tools": { "items": { "$ref": "#/components/schemas/SubToolEntryResponse" }, "type": "array", "title": "Sub Tools" } }, "type": "object", "required": [ "name", "description", "category", "enabled" ], "title": "ToolConfigEntryResponse" }, "ToolConfigResponse": { "properties": { "tools": { "items": { "$ref": "#/components/schemas/ToolConfigEntryResponse" }, "type": "array", "title": "Tools" } }, "type": "object", "required": [ "tools" ], "title": "ToolConfigResponse" }, "ToolConfigUpdate": { "properties": { "tools": { "items": { "$ref": "#/components/schemas/ToolConfigUpdateEntry" }, "type": "array", "title": "Tools" } }, "type": "object", "required": [ "tools" ], "title": "ToolConfigUpdate" }, "ToolConfigUpdateEntry": { "properties": { "name": { "type": "string", "title": "Name" }, "enabled": { "type": "boolean", "title": "Enabled" }, "sub_tools": { "anyOf": [ { "items": { "$ref": "#/components/schemas/SubToolPermissionUpdate" }, "type": "array" }, { "type": "null" } ], "title": "Sub Tools" } }, "type": "object", "required": [ "name", "enabled" ], "title": "ToolConfigUpdateEntry" }, "UserProfileResponse": { "properties": { "id": { "type": "string", "title": "Id" }, "user_id": { "type": "string", "title": "User Id" }, "phone": { "type": "string", "title": "Phone" }, "timezone": { "type": "string", "title": "Timezone" }, "soul_text": { "type": "string", "title": "Soul Text" }, "user_text": { "type": "string", "title": "User Text" }, "heartbeat_text": { "type": "string", "title": "Heartbeat Text" }, "preferred_channel": { "type": "string", "title": "Preferred Channel" }, "channel_identifier": { "type": "string", "title": "Channel Identifier" }, "heartbeat_opt_in": { "type": "boolean", "title": "Heartbeat Opt In" }, "heartbeat_frequency": { "type": "string", "title": "Heartbeat Frequency" }, "heartbeat_max_daily": { "type": "integer", "title": "Heartbeat Max Daily", "default": 0 }, "onboarding_complete": { "type": "boolean", "title": "Onboarding Complete" }, "is_active": { "type": "boolean", "title": "Is Active" }, "data_sharing_consent": { "type": "boolean", "title": "Data Sharing Consent", "default": false }, "data_sharing_consent_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Data Sharing Consent At" }, "created_at": { "type": "string", "title": "Created At" }, "updated_at": { "type": "string", "title": "Updated At" } }, "type": "object", "required": [ "id", "user_id", "phone", "timezone", "soul_text", "user_text", "heartbeat_text", "preferred_channel", "channel_identifier", "heartbeat_opt_in", "heartbeat_frequency", "onboarding_complete", "is_active", "created_at", "updated_at" ], "title": "UserProfileResponse" }, "UserProfileUpdate": { "properties": { "phone": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone" }, "timezone": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Timezone" }, "soul_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Soul Text" }, "user_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Text" }, "heartbeat_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Heartbeat Text" }, "heartbeat_opt_in": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Heartbeat Opt In" }, "heartbeat_frequency": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Heartbeat Frequency" }, "heartbeat_max_daily": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Heartbeat Max Daily" } }, "type": "object", "title": "UserProfileUpdate", "description": "Fields the client is allowed to update on the current user.\n\n``onboarding_complete`` is deliberately not writable here. It is owned by\nthe backend (set by ``OnboardingSubscriber`` when the LLM deletes\nBOOTSTRAP.md or heuristic evidence appears) so the conversational\nonboarding can't be short-circuited by the UI.\n\n``data_sharing_consent`` is deliberately not writable here either:\nit has its own dedicated endpoint (``PUT /api/user/data-sharing-consent``)\nthat always stamps ``data_sharing_consent_at``. Routing it through\nthis generic patch endpoint would lose the timestamp guarantee.\n\n``model_config`` pins ``extra=\"ignore\"`` so unknown fields (including\n``data_sharing_consent`` if a client tries to slip it through here)\nare silently dropped. This is the contract the dedicated-endpoint\ntest relies on. If pydantic ever flips the global default to\n``\"forbid\"``, this declaration keeps the contract stable." }, "ValidationError": { "properties": { "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "type": "array", "title": "Location" }, "msg": { "type": "string", "title": "Message" }, "type": { "type": "string", "title": "Error Type" }, "input": { "title": "Input" }, "ctx": { "type": "object", "title": "Context" } }, "type": "object", "required": [ "loc", "msg", "type" ], "title": "ValidationError" }, "_ChatAccepted": { "properties": { "request_id": { "type": "string", "title": "Request Id" } }, "type": "object", "required": [ "request_id" ], "title": "_ChatAccepted" } } } }