{ "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: a sync DB call from an async\nhandler can block the event loop, and during an incident a healthcheck\nthat waits on the same DB can pile up alongside whatever already broke.\nUse ``/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/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/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/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.", "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/storage/config": { "get": { "summary": "Get Storage Config", "description": "Return server-level storage configuration.", "operationId": "get_storage_config_api_user_storage_config_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StorageConfigResponse" } } } } } }, "put": { "summary": "Update Storage Config", "description": "Update server-level storage configuration.", "operationId": "update_storage_config_api_user_storage_config_put", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StorageConfigUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StorageConfigResponse" } } } }, "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/sessions": { "get": { "summary": "List Sessions", "description": "List sessions with message counts, ordered by last_message_at DESC.", "operationId": "list_sessions_api_user_sessions_get", "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 200, "minimum": 1, "default": 50, "title": "Limit" } }, { "name": "offset", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0, "title": "Offset" } }, { "name": "is_active", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Active" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionListResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/sessions/{session_id}": { "get": { "summary": "Get Session", "description": "Get a full conversation transcript with tool interactions.", "operationId": "get_session_api_user_sessions__session_id__get", "parameters": [ { "name": "session_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Session Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionDetailResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/sessions/{session_id}/system-prompt": { "get": { "summary": "Get Session 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 ``organize_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_session_system_prompt_api_user_sessions__session_id__system_prompt_get", "parameters": [ { "name": "session_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Session Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionSystemPromptResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/user/sessions/{session_id}/messages/batch": { "delete": { "summary": "Delete Messages Batch", "description": "Delete specific messages from a session by their sequence numbers.", "operationId": "delete_messages_batch_api_user_sessions__session_id__messages_batch_delete", "parameters": [ { "name": "session_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Session Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchDeleteRequest" } } } }, "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/sessions/{session_id}/messages/{seq}": { "delete": { "summary": "Delete Single Message", "description": "Delete a single message from a session by its sequence number.", "operationId": "delete_single_message_api_user_sessions__session_id__messages__seq__delete", "parameters": [ { "name": "session_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Session Id" } }, { "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/sessions/{session_id}/messages": { "delete": { "summary": "Delete Conversation History", "description": "Delete all messages from a session, preserving memory and the session itself.\n\nResets the compaction pointer and system prompt so the conversation\ncontinues with a clean slate while retaining compacted memory.", "operationId": "delete_conversation_history_api_user_sessions__session_id__messages_delete", "parameters": [ { "name": "session_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Session Id" } } ], "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/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.", "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 domain-specific tools can be toggled. Attempts to disable\ncore tools are silently ignored.\n\nEach entry may include ``disabled_sub_tools`` to control individual\ntools within a factory group.", "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": { "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": "" }, "session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Session Id" }, "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" } }, "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" } }, "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" }, "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" }, "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" }, "is_active": { "type": "boolean", "title": "Is Active" }, "channel": { "type": "string", "title": "Channel", "default": "" }, "initial_system_prompt": { "type": "string", "title": "Initial System Prompt", "default": "" }, "last_compacted_seq": { "type": "integer", "title": "Last Compacted Seq", "default": 0 }, "messages": { "items": { "$ref": "#/components/schemas/SessionMessage" }, "type": "array", "title": "Messages" } }, "type": "object", "required": [ "session_id", "user_id", "created_at", "last_message_at", "is_active", "messages" ], "title": "SessionDetailResponse" }, "SessionListItem": { "properties": { "session_id": { "type": "string", "title": "Session Id" }, "channel": { "type": "string", "title": "Channel", "default": "" }, "is_active": { "type": "boolean", "title": "Is Active" }, "message_count": { "type": "integer", "title": "Message Count" }, "created_at": { "type": "string", "title": "Created At" }, "last_message_at": { "type": "string", "title": "Last Message At" } }, "type": "object", "required": [ "session_id", "is_active", "message_count", "created_at", "last_message_at" ], "title": "SessionListItem" }, "SessionListResponse": { "properties": { "total": { "type": "integer", "title": "Total" }, "items": { "items": { "$ref": "#/components/schemas/SessionListItem" }, "type": "array", "title": "Items" } }, "type": "object", "required": [ "total", "items" ], "title": "SessionListResponse" }, "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) rather than pulled from the\nsession's frozen ``initial_system_prompt`` column. Use this when\nthe UI needs the current prompt; use ``initial_system_prompt`` on\n``SessionDetailResponse`` when the historical first-turn prompt is\nwhat's wanted." }, "StorageConfigResponse": { "properties": { "storage_provider": { "type": "string", "title": "Storage Provider" }, "file_storage_base_dir": { "type": "string", "title": "File Storage Base Dir" }, "dropbox_access_token_set": { "type": "boolean", "title": "Dropbox Access Token Set" }, "google_drive_credentials_json_set": { "type": "boolean", "title": "Google Drive Credentials Json Set" } }, "type": "object", "required": [ "storage_provider", "file_storage_base_dir", "dropbox_access_token_set", "google_drive_credentials_json_set" ], "title": "StorageConfigResponse" }, "StorageConfigUpdate": { "properties": { "storage_provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Storage Provider" }, "file_storage_base_dir": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "File Storage Base Dir" }, "dropbox_access_token": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Dropbox Access Token" }, "google_drive_credentials_json": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Google Drive Credentials Json" } }, "type": "object", "title": "StorageConfigUpdate" }, "SubToolEntryResponse": { "properties": { "name": { "type": "string", "title": "Name" }, "description": { "type": "string", "title": "Description" }, "enabled": { "type": "boolean", "title": "Enabled" }, "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", "enabled" ], "title": "SubToolEntryResponse" }, "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": "" }, "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" }, "disabled_sub_tools": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Disabled 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" }, "session_id": { "type": "string", "title": "Session Id" } }, "type": "object", "required": [ "request_id", "session_id" ], "title": "_ChatAccepted" } } } }