{"openapi":"3.1.0","info":{"title":"Stitch API","description":"\n## Stitch Messaging API\n\nA secure, real-time messaging platform with support for:\n\n- **Messages**: Create, read, search, and traverse conversation threads\n- **Users**: Profile management, search, and contact verification\n- **Authentication**: API keys, password login, OAuth2 tokens, session management\n- **Managed Users**: Delegate access to bot/proxy accounts\n- **Channels**: Group messages and control visibility with channel membership\n- **Imports**: Import messages from external sources (Cursor IDE, audio transcription)\n- **Links**: Stitch one existing message under another\n- **Files**: Upload and attach files to messages\n- **Real-time**: WebSocket notifications for new messages\n\n### Message View Modes\n\nThree different views for fetching messages:\n\n| Mode | Endpoint | Description |\n|------|----------|-------------|\n| **Timeline** | `GET /v1/messages/timeline` | Chronological feed of all messages visible to the user. Shows every message regardless of thread position. Ideal for bots and activity feeds. |\n| **Inbox** | `GET /v1/messages/inbox` | Shows leaf nodes (most recent) in each conversation thread where the user is involved. Best for conversation-focused UIs. |\n| **History** | `GET /v1/messages/history` | Shows root messages (thread origins) for threads where the user has participated. Useful for seeing all conversations started. |\n\n### Authentication\n\nMost endpoints require authentication via Bearer token or an API key:\n```\nAuthorization: Bearer <access_token>\nx-api-key: <api_key>\n```\n\nA bearer token wins when both are sent. An API key is the same principal and scopes as exchanging it at `POST /v1/auth/token`.\n\nObtain tokens via:\n- `POST /v1/auth/token` - Exchange API key for token\n- `POST /v1/auth/password/login` - Password-based login\n- `POST /v1/auth/register` - Create new account\n\n### Scopes\n\nAccess is controlled by scopes on the session:\n- `messages.read` - Read messages\n- `messages.write` - Create/update/delete messages\n- `realtime.connect` - Connect to WebSocket\n    ","version":"1.0.0"},"paths":{"/v1/admin/metrics/messages-per-day":{"get":{"tags":["admin"],"summary":"Messages per day by user","description":"Aggregated message counts by calendar day and author. Admin only.","operationId":"messages_per_day_v1_admin_metrics_messages_per_day_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"from_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Start date (YYYY-MM-DD)","title":"From Date"},"description":"Start date (YYYY-MM-DD)"},{"name":"to_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"End date (YYYY-MM-DD)","title":"To Date"},"description":"End date (YYYY-MM-DD)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"description":"Max rows to return","default":1000,"title":"Limit"},"description":"Max rows to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response Messages Per Day V1 Admin Metrics Messages Per Day Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/.well-known/jwks.json":{"get":{"tags":["auth"],"summary":"JWKS (legacy stub)","description":"Legacy JWKS endpoint retained for older clients.\n\nStitch uses opaque server-side sessions (`st_session_…`), not JWTs.\nThis endpoint always returns an empty key set: `{\"keys\": []}`.","operationId":"get_jwks","responses":{"200":{"description":"Empty JWKS document","content":{"application/json":{"schema":{},"example":{"keys":[]}}}}}}},"/v1/auth/token":{"post":{"tags":["auth"],"summary":"Exchange API key for opaque session","description":"Exchange an API key for an opaque session token (OAuth2-shaped response).\n\n**Authentication:** Requires `x-api-key` with a valid API key.\n\n**Request Body (optional):**\n- `requested_permissions` (alias `requested_scopes`): space-delimited permissions to request\n- `device_id`: optional device identifier stored on the session\n- `aud` / `cnf` / `act`: accepted for compatibility; ignored (not JWT claims)\n\n**Response:**\n- `access_token`: opaque `st_session_{id}.{secret}` (use as `Authorization: Bearer …`)\n- `token_type`: `Bearer`\n- `expires_in`: session TTL (`STITCH_SESSION_TTL`, default 30 days)\n- Also sets HttpOnly `stitch_session` cookie (browsers); M2M clients use the body Bearer\n\n**Permissions:** Frozen as the intersection of:\n1. Requested permissions (from payload)\n2. Credential ceiling (`scopes_cap` on the API key)\n3. Principal grant on the user\n\n**Partner Access:** Requires `has_api_access` on the user account.\n\nClients should cache the session and remint on expiry or 401 — not per request.\nOptional `POST /v1/auth/sessions/refresh` extends the same token in place.","operationId":"exchange_api_key_for_token","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TokenRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Session minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Missing x-api-key header"},"401":{"description":"Invalid API key"},"403":{"description":"User not allowed or partner access required"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/keys":{"get":{"tags":["auth"],"summary":"List Own Api Keys","operationId":"list_own_api_keys_v1_auth_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Own Api Keys V1 Auth Keys Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/keys/{key_id}":{"delete":{"tags":["auth"],"summary":"Revoke Api Key","operationId":"revoke_api_key_v1_auth_keys__key_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revoke Api Key V1 Auth Keys  Key Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/keys/self":{"post":{"tags":["auth"],"summary":"Create Own Api Key","operationId":"create_own_api_key_v1_auth_keys_self_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Own Api Key V1 Auth Keys Self Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/session":{"get":{"tags":["auth"],"summary":"Get current session","description":"Authoritative session metadata for clients. Cookie or Bearer session required. Pure read: does not mutate stored permissions.","operationId":"get_session_v1_auth_session_get","responses":{"200":{"description":"Current session","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Session V1 Auth Session Get"}}}},"401":{"description":"Not authenticated"}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/sessions/refresh":{"post":{"tags":["auth"],"summary":"Extend opaque session","description":"Extend the current opaque session in place.\n\nPresent the session via `Authorization: Bearer` or `stitch_session` cookie.\nReturns the **same** `access_token` string with a new `expires_at` / `expires_in`.\nDoes not mint a new secret (not JWT refresh-token rotation).\nEmpty frozen permission sets may be healed onto the same session row.","operationId":"refresh_session_v1_auth_sessions_refresh_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"X-Correlation-Id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Correlation-Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Session extended","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Refresh Session V1 Auth Sessions Refresh Post"}}}},"401":{"description":"Missing or invalid session"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/password/login":{"post":{"tags":["auth"],"summary":"Password Login","operationId":"password_login_v1_auth_password_login_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/password/change":{"post":{"tags":["auth"],"summary":"Change password","description":"Change password for the authenticated user. Requires current password verification.","operationId":"change_password_v1_auth_password_change_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Password changed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Missing passwords or weak password"},"401":{"description":"Invalid current password"},"403":{"description":"Managed users cannot have passwords"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/contacts/endpoint/request":{"post":{"tags":["auth"],"summary":"Request endpoint verification","description":"Create a verification challenge for a webhook endpoint. The server will POST a nonce to the endpoint during verification.","operationId":"request_endpoint_verification_v1_auth_contacts_endpoint_request_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Challenge created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChallengeResponse"}}}},"400":{"description":"Invalid endpoint"},"500":{"description":"Failed to create challenge"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/contacts/endpoint/verify":{"post":{"tags":["auth"],"summary":"Verify endpoint with challenge","description":"Verify a webhook endpoint by POSTing a nonce and checking the response.\n\nThe server will try multiple methods:\n1. POST JSON with nonce\n2. POST plain text with nonce\n3. GET with nonce as query parameter\n\nThe endpoint must echo the nonce back in the response.","operationId":"verify_endpoint_with_challenge_v1_auth_contacts_endpoint_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointVerifyRequest"}}},"required":true},"responses":{"200":{"description":"Endpoint verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationResponse"}}}},"400":{"description":"Nonce mismatch or invalid endpoint"},"404":{"description":"No active challenge"},"500":{"description":"Endpoint request failed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"Revoke the current opaque session (cookie or Bearer) and clear session cookies. Idempotent.","operationId":"logout_v1_auth_logout_post","responses":{"200":{"description":"Logged out successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogoutResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/contacts/email/request":{"post":{"tags":["auth"],"summary":"Request email verification","description":"Send a verification code to the specified email address.","operationId":"request_email_verification_v1_auth_contacts_email_request_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Verification code sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChallengeResponse"}}}},"400":{"description":"Invalid email"},"500":{"description":"Failed to send verification code"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/contacts/email/verify":{"post":{"tags":["auth"],"summary":"Verify email with code","description":"Verify an email address using the 6-digit code sent via email.","operationId":"verify_email_with_code_v1_auth_contacts_email_verify_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Email verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationResponse"}}}},"400":{"description":"Invalid code or missing parameters"},"500":{"description":"Failed to verify email"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/contacts/phone/request":{"post":{"tags":["auth"],"summary":"Request phone verification","description":"Send a verification code via SMS to the specified phone number.","operationId":"request_phone_verification_v1_auth_contacts_phone_request_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Verification code sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChallengeResponse"}}}},"400":{"description":"Invalid phone number"},"500":{"description":"Failed to send verification code"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/contacts/phone/verify":{"post":{"tags":["auth"],"summary":"Verify phone with code","description":"Verify a phone number using the 6-digit code sent via SMS.","operationId":"verify_phone_with_code_v1_auth_contacts_phone_verify_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Phone verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationResponse"}}}},"400":{"description":"Invalid code or missing parameters"},"500":{"description":"Failed to verify phone"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/password/reset/request":{"post":{"tags":["auth"],"summary":"Request password reset","description":"Request a password reset code sent via email.\n\nProvide either `email` or `user_tag`. If multiple accounts share the email, returns 409 to require disambiguation via user_tag.\n\nFor security, always returns success even if the email/user doesn't exist.","operationId":"request_password_reset_code_v1_auth_password_reset_request_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetRequestBody"}}},"required":true},"responses":{"200":{"description":"Reset code sent (or user not found)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChallengeResponse"}}}},"400":{"description":"Missing email or user_tag"},"409":{"description":"Multiple accounts found for email"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/password/reset":{"post":{"tags":["auth"],"summary":"Complete password reset","description":"Complete password reset using the verification code.\n\nRequires the verification code from the email and a new password.\nOn success, automatically signs the user in (opaque session cookie + body token).","operationId":"apply_password_reset_with_code_v1_auth_password_reset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetBody"}}},"required":true},"responses":{"200":{"description":"Password reset successful, user signed in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Invalid code or weak password"},"409":{"description":"Multiple accounts found for email"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/act-as/return":{"post":{"tags":["auth"],"summary":"Act As Return","description":"Restore the manager session from stitch_mgr_session backup cookie.\n\nRegistered before `/act-as/{subject_uid}` so `return` is not captured as a uid.","operationId":"act_as_return_v1_auth_act_as_return_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/act-as/{subject_uid}":{"post":{"tags":["auth"],"summary":"Act As Subject","description":"Create a delegated session acting as subject_uid.","operationId":"act_as_subject_v1_auth_act_as__subject_uid__post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"subject_uid","in":"path","required":true,"schema":{"type":"string","title":"Subject Uid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/tags":{"get":{"tags":["enrichment"],"summary":"Get available tags","description":"Get all distinct tags from messages visible to the current user.","operationId":"get_user_tags_v1_messages_tags_get","responses":{"200":{"description":"List of tag names","content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Response Get User Tags V1 Messages Tags Get"}}}},"500":{"description":"Failed to fetch tags"}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/{message_id}/tags":{"patch":{"tags":["enrichment"],"summary":"Update message tags","description":"Replace tags for a message.\n\nRequires `messages.write` scope and visibility to the message.\nTags are enrichment operations - collaborative. Anyone who can see the message can tag it.","operationId":"update_message_tags_v1_messages__message_id__tags_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTagsRequest"}}}},"responses":{"200":{"description":"Updated message with new tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageOutput"}}}},"400":{"description":"Missing tags in body"},"403":{"description":"Insufficient scope"},"404":{"description":"Message not found"},"422":{"description":"Invalid tag format"},"500":{"description":"Failed to update tags"}}}},"/v1/messages/tags/batch":{"patch":{"tags":["enrichment"],"summary":"Batch update message tags","description":"Replace tags for multiple messages.\nRequires `messages.write` scope and visibility to the messages.","operationId":"batch_update_message_tags_v1_messages_tags_batch_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTagsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Batch Update Message Tags V1 Messages Tags Batch Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/{message_id}/subject":{"patch":{"tags":["enrichment"],"summary":"Add subject to message","description":"Add a subject to a message that doesn't have one.\n\nRequires `messages.write` scope and visibility to the message.\nSubjects can only be added, not modified. If the message already has a subject, this will fail.","operationId":"add_message_subject_v1_messages__message_id__subject_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSubjectRequest"}}}},"responses":{"200":{"description":"Message with added subject","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageOutput"}}}},"400":{"description":"Message already has a subject or invalid subject"},"403":{"description":"Insufficient scope"},"404":{"description":"Message not found"},"422":{"description":"Subject too long (max 72 characters)"},"500":{"description":"Failed to add subject"}}}},"/v1/links/messages/{message_id}/incoming":{"get":{"tags":["enrichment"],"summary":"Get incoming links","description":"Get messages that link TO the specified message.\n\nBy default, only shows links created by the current user. Set `show_all_links=true` to see all links.","operationId":"get_incoming_links_v1_links_messages__message_id__incoming_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of links to skip","default":0,"title":"Skip"},"description":"Number of links to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of links to return","default":15,"title":"Limit"},"description":"Number of links to return"},{"name":"show_all_links","in":"query","required":false,"schema":{"type":"boolean","description":"Show all links, not just user's links","default":false,"title":"Show All Links"},"description":"Show all links, not just user's links"}],"responses":{"200":{"description":"Paginated list of messages linking to this message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Failed to get incoming links"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/links/messages/{message_id}/outgoing":{"get":{"tags":["enrichment"],"summary":"Get outgoing links","description":"Get messages that the specified message links TO.\n\nBy default, only shows links created by the current user. Set `show_all_links=true` to see all links.","operationId":"get_outgoing_links_v1_links_messages__message_id__outgoing_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of links to skip","default":0,"title":"Skip"},"description":"Number of links to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of links to return","default":15,"title":"Limit"},"description":"Number of links to return"},{"name":"show_all_links","in":"query","required":false,"schema":{"type":"boolean","description":"Show all links, not just user's links","default":false,"title":"Show All Links"},"description":"Show all links, not just user's links"}],"responses":{"200":{"description":"Paginated list of messages this message links to","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Failed to get outgoing links"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/links/messages/{message_id_from}/{message_id_to}":{"post":{"tags":["enrichment"],"summary":"Create link","description":"Create a directional link from one message to another. Requires `messages.write` scope.","operationId":"create_link_v1_links_messages__message_id_from___message_id_to__post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id_from","in":"path","required":true,"schema":{"type":"string","title":"Message Id From"}},{"name":"message_id_to","in":"path","required":true,"schema":{"type":"string","title":"Message Id To"}}],"responses":{"200":{"description":"Link created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"403":{"description":"Insufficient scope"},"500":{"description":"Failed to create link"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["enrichment"],"summary":"Delete link","description":"Delete an existing link between two messages. Requires `messages.write` scope.","operationId":"delete_link_v1_links_messages__message_id_from___message_id_to__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id_from","in":"path","required":true,"schema":{"type":"string","title":"Message Id From"}},{"name":"message_id_to","in":"path","required":true,"schema":{"type":"string","title":"Message Id To"}}],"responses":{"200":{"description":"Link deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"403":{"description":"Insufficient scope"},"500":{"description":"Failed to delete link"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/recipients/add":{"post":{"tags":["enrichment"],"summary":"Add recipients to messages","description":"Add recipients to one or many messages.\n\nBody can include either `message_id` or `message_ids[]`.\n`recipients` can be a list of user tags (strings), `uid:UID` strings, or recipient objects.\n\n**Recipient object format:**\n- `user_tag` or `uid`: User identifier (required)\n- `public` (default: true): CC (true) vs BCC (false) visibility\n- `notify` (default: true): Whether to send notification to this recipient\n\n    **Propagation (Deprecated):**\n- `propagation.strategy`: Controls how recipients are added to related messages. \n  **Note**: This parameter is deprecated in favor of client-side resolution and explicit `message_ids`.\n  - `\"NONE\"` (default): Only add to specified message(s)\n  - `\"ANCESTORS\"`: Add to visible ancestors (stops when parent is not visible)\n  - `\"TREE\"`: Add to entire conversation tree (ancestors + descendants + siblings)\n\n\n**Idempotent:** Duplicate recipient edges are not created. First add wins for `added_by` tracking.\n\n**Notifications:** Controlled by per-recipient `notify` flag (defaults to true). When propagation is used,\nall affected messages are batched into a single notification per recipient (propagation is not sent to receivers).\n\nRequires `messages.write` scope.","operationId":"add_recipients_v1_recipients_add_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddRecipientsRequest"}}},"required":true},"responses":{"200":{"description":"Recipients added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddRecipientsResponse"}}}},"400":{"description":"Missing message_id or recipients"},"403":{"description":"Insufficient scope"},"500":{"description":"Failed to add recipients"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/recipients/remove":{"delete":{"tags":["enrichment"],"summary":"Remove recipient from messages","description":"Remove a recipient from one or many messages.\n\nBody must include `recipient_uid` and either `message_id` or `message_ids[]`.\n- `propagate_to_descendants` (default false): cascade removal to children\n\nRequires `messages.write` scope.","operationId":"remove_recipient_v1_recipients_remove_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveRecipientRequest"}}},"required":true},"responses":{"200":{"description":"Recipient removed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddRecipientsResponse"}}}},"400":{"description":"Missing message_id or recipient_uid"},"403":{"description":"Insufficient scope"},"500":{"description":"Failed to remove recipient"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/{message_id}/channels":{"patch":{"tags":["enrichment"],"summary":"Update message channels","description":"Update which channels a message belongs to.\n\nReplaces all existing channel associations with the provided list.\nUse empty list to remove message from all channels.\n\nRequires `messages.write` scope and:\n- User must be member of all target channels\n- User must be able to see the message (visibility-based)","operationId":"update_message_channels_v1_messages__message_id__channels_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChannelsRequest"}}}},"responses":{"200":{"description":"Message channels updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateChannelsResponse"}}}},"403":{"description":"Insufficient scope or not member of channel"},"404":{"description":"Message not found"},"500":{"description":"Failed to update channels"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/similar/{message_id}":{"get":{"tags":["messages"],"summary":"Get similar messages","description":"Find messages similar to the given message based on token and multi-gram overlap.\nPrioritizes consecutive tokens (phrases) quadratically (n^2).\nRepetitions in both source and candidate amplify the score via dot product.","operationId":"get_similar_messages_v1_messages_similar__message_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Max number of similar messages to return","default":5,"title":"Limit"},"description":"Max number of similar messages to return"},{"name":"max_n","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"description":"Maximum n-gram length to consider (e.g. 3 for trigrams)","default":3,"title":"Max N"},"description":"Maximum n-gram length to consider (e.g. 3 for trigrams)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SimilarMessageResponse"},"title":"Response Get Similar Messages V1 Messages Similar  Message Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/search/similar/{message_id}":{"get":{"tags":["messages"],"summary":"Get similar messages (alias)","description":"Find messages similar to the given message based on token and multi-gram overlap.","operationId":"get_similar_messages_v1_messages_search_similar__message_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Max number of similar messages to return","default":5,"title":"Limit"},"description":"Max number of similar messages to return"},{"name":"max_n","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"description":"Maximum n-gram length to consider (e.g. 3 for trigrams)","default":3,"title":"Max N"},"description":"Maximum n-gram length to consider (e.g. 3 for trigrams)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SimilarMessageResponse"},"title":"Response Get Similar Messages V1 Messages Search Similar  Message Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/timeline/export":{"get":{"tags":["messages"],"summary":"Export timeline messages","description":"Export a JSON timeline bundle (metadata + `messages[]`) for the authenticated user.\n\nDefault cutoff: yesterday at 4pm Eastern. If `days` is set, cutoff is now minus `days` (UTC).\nReturns messages in reverse-chronological order (newest -> oldest), matching `stitch-bots/experimental/export_timeline.py`.","operationId":"export_user_timeline_v1_messages_timeline_export_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":3650,"minimum":1},{"type":"null"}],"description":"Export messages from the past N days (UTC). Default: since yesterday at 4pm Eastern.","title":"Days"},"description":"Export messages from the past N days (UTC). Default: since yesterday at 4pm Eastern."},{"name":"channel_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional channel ID to filter; user must be a member","title":"Channel Id"},"description":"Optional channel ID to filter; user must be a member"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Export User Timeline V1 Messages Timeline Export Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages":{"post":{"tags":["messages"],"summary":"Create messages","description":"Create one or many messages.\n\nAccepts:\n- Single MessageInput object\n- Object with `messages: MessageInput[]`\n- Raw array of MessageInput\n\n**Recipients:**\n- String format: `\"alice\"` or `\"@alice\"` (defaults to `notify: true`, `public: true`)\n- Object format: `{user_tag: \"alice\", public: true, notify: false}` for per-recipient control\n- The `notify` flag controls whether notification is sent (input-only, not stored)\n\n**Idempotent:** When adding recipients to existing messages, duplicate edges are not created.\n\nReturns a list of per-message results to allow partial success and itemized errors.\nFor multi-message input, messages are chained as replies to the previous successful one.\n\nRequires `messages.write` scope.","operationId":"create_messages_unified_v1_messages_post","requestBody":{"content":{"application/json":{"schema":{"title":"Payload"}}},"required":true},"responses":{"200":{"description":"Messages created (check individual results for success/error)","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/MessageCreateResult"},"type":"array","title":"Response Create Messages Unified V1 Messages Post"}}}},"400":{"description":"Invalid request body"},"403":{"description":"Insufficient scope"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/{message_id}":{"delete":{"tags":["messages"],"summary":"Delete message","description":"Delete a message and optionally all its descendants.\n\nRequires `messages.write` scope. Only the message author or their manager can delete messages.\nNo admin bypass on public router - admins must use internal router.","operationId":"delete_message_v1_messages__message_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}},{"name":"delete_descendants","in":"query","required":false,"schema":{"type":"boolean","description":"Delete all descendants of the message","default":false,"title":"Delete Descendants"},"description":"Delete all descendants of the message"}],"responses":{"200":{"description":"Message deleted","content":{"application/json":{"schema":{}}}},"403":{"description":"Insufficient scope or not authorized to delete"},"404":{"description":"Message not found"},"500":{"description":"Failed to delete message"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["messages"],"summary":"Get message","description":"Fetch a single message by ID, enforcing standard visibility rules.","operationId":"get_message_v1_messages__message_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"responses":{"200":{"description":"Message details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageOutput"}}}},"404":{"description":"Message not found or not visible"},"500":{"description":"Failed to load message"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/public":{"get":{"tags":["messages"],"summary":"Get public messages","description":"Get public messages with pagination. Shows only leaf nodes (most recent in each thread). No authentication required.","operationId":"get_public_messages_v1_messages_public_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of messages to skip","default":0,"title":"Skip"},"description":"Number of messages to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of messages to return","default":15,"title":"Limit"},"description":"Number of messages to return"}],"responses":{"200":{"description":"Paginated public messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Failed to load messages"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/inbox":{"get":{"tags":["messages"],"summary":"Get inbox messages","description":"Get messages for the current user with pagination.\n\nReturns the latest message in each conversation thread where the user is involved\n(either as recipient or as sender with actual recipients).\n\nPass unread_only=true to keep only threads that still have unread messages.\nThose leaves stay sorted by timestamp, newest first.","operationId":"get_user_messages_v1_messages_inbox_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of messages to skip","default":0,"title":"Skip"},"description":"Number of messages to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of messages to return","default":15,"title":"Limit"},"description":"Number of messages to return"},{"name":"channel_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional channel ID to filter messages; user must be a member","title":"Channel Id"},"description":"Optional channel ID to filter messages; user must be a member"},{"name":"unread_only","in":"query","required":false,"schema":{"type":"boolean","description":"When true, return only leaves of threads that have unread messages","default":false,"title":"Unread Only"},"description":"When true, return only leaves of threads that have unread messages"}],"responses":{"200":{"description":"Paginated inbox messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Failed to get messages"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/history":{"get":{"tags":["messages"],"summary":"Get message history","description":"Get root messages (thread origins) for threads the user is involved in at any point.\n\nReturns the root of each unique thread where the user has sent at least one message,\nin any branch of the thread (subject to visibility permissions). Sorted by most recent\nuser activity in each thread. Useful for showing all conversations the user participated in.","operationId":"get_user_history_roots_v1_messages_history_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of messages to skip","default":0,"title":"Skip"},"description":"Number of messages to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of messages to return","default":6,"title":"Limit"},"description":"Number of messages to return"},{"name":"channel_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional channel ID to filter; user must be a member","title":"Channel Id"},"description":"Optional channel ID to filter; user must be a member"}],"responses":{"200":{"description":"Paginated history messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Failed to load history"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/timeline":{"get":{"tags":["messages"],"summary":"Get timeline messages","description":"Get all messages visible to the current user in reverse chronological order.\n\n**Timeline Mode** - Returns a flat, chronological feed of all individual messages visible to the user.\nUnlike `/inbox` (which shows conversation leaf nodes) or `/history` (which shows thread roots),\ntimeline shows every message regardless of thread structure.\n\nThis endpoint is particularly useful for:\n- Bot services that need to process messages in chronological order\n- Building activity feeds\n- Fetching recent context across all conversations\n\n**Visibility:** Returns messages where the user is:\n- The author\n- A recipient (CC or BCC)\n- A member of a channel the message is in\n- Or the message is public","operationId":"get_user_timeline_v1_messages_timeline_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of messages to skip","default":0,"title":"Skip"},"description":"Number of messages to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of messages to return","default":15,"title":"Limit"},"description":"Number of messages to return"},{"name":"channel_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional channel ID to filter; user must be a member","title":"Channel Id"},"description":"Optional channel ID to filter; user must be a member"}],"responses":{"200":{"description":"Paginated timeline messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Failed to load timeline"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/traverse-from/{message_id}":{"get":{"tags":["messages"],"summary":"Traverse messages","description":"Unified traversal: get the origin message plus related messages within specified depths.\n\nParameters:\n- `up_depth`: How many parent levels to traverse (0-100)\n- `down_depth`: How many child levels to traverse (0-100)\n- `get_replies`: Include child reply metadata for each message\n- `get_children`: Expand and include one-hop children for all returned nodes\n- `default_path_only`: Outgoing direction returns the linear chain of `default_outgoing` children instead of every sibling. The upward direction is unchanged. This parameter will eventually apply to incoming edges too, if and when defaults exist in that direction.\n\nReturns the origin message and a list of related messages within the visibility rules.","operationId":"traverse_from_v1_messages_traverse_from__message_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}},{"name":"up_depth","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":0,"description":"Number of parent levels to traverse","default":2,"title":"Up Depth"},"description":"Number of parent levels to traverse"},{"name":"down_depth","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":0,"description":"Number of child levels to traverse","default":2,"title":"Down Depth"},"description":"Number of child levels to traverse"},{"name":"edge_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(replies|links)$","description":"The edge collection to traverse","default":"replies","title":"Edge Type"},"description":"The edge collection to traverse"},{"name":"get_replies","in":"query","required":false,"schema":{"type":"boolean","description":"Include child replies for each message (metadata only)","default":true,"title":"Get Replies"},"description":"Include child replies for each message (metadata only)"},{"name":"get_children","in":"query","required":false,"schema":{"type":"boolean","description":"Expand and include one-hop children for all nodes","default":false,"title":"Get Children"},"description":"Expand and include one-hop children for all nodes"},{"name":"default_path_only","in":"query","required":false,"schema":{"type":"boolean","description":"Follow default_outgoing downward instead of the outgoing fan-out. Incoming defaults are not implemented.","default":false,"title":"Default Path Only"},"description":"Follow default_outgoing downward instead of the outgoing fan-out. Incoming defaults are not implemented."}],"responses":{"200":{"description":"Origin message and related messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraversalResponse"}}}},"404":{"description":"Origin message not found or not visible"},"500":{"description":"Failed to traverse messages"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/search":{"get":{"tags":["messages"],"summary":"Search messages","description":"Search for messages by tags and content.\n\nParameters:\n- `q`: Content search query (future)\n- `tags`: Comma-separated list of tags to filter by\n- `match`: How to match tags - \"any\" (OR) or \"all\" (AND)\n\nReturns messages visible to the current user (or public messages for anonymous users).","operationId":"search_messages_v1_messages_search_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Content query","title":"Q"},"description":"Content query"},{"name":"query","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Content query alias","title":"Query"},"description":"Content query alias"},{"name":"tags","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated tags","title":"Tags"},"description":"Comma-separated tags"},{"name":"match","in":"query","required":false,"schema":{"type":"string","pattern":"^(any|all)$","description":"Tag matching mode: 'any' (OR) or 'all' (AND)","default":"any","title":"Match"},"description":"Tag matching mode: 'any' (OR) or 'all' (AND)"},{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Deprecated, ignored","title":"Scope"},"description":"Deprecated, ignored"},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of messages to skip","default":0,"title":"Skip"},"description":"Number of messages to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of messages to return","default":15,"title":"Limit"},"description":"Number of messages to return"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Search failed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/{message_id}/reply_order":{"patch":{"tags":["messages"],"summary":"Update reply order","description":"Update the custom reply ordering for a message.\n\nRequires `messages.write` scope. Only the message author or their manager can change reply order.\nNo admin bypass on public router.\n\nSet `reply_order` to a list of reply IDs in desired order, or null to clear custom ordering.","operationId":"update_message_reply_order_v1_messages__message_id__reply_order_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReplyOrderRequest"}}}},"responses":{"200":{"description":"Updated message with new reply order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageOutput"}}}},"400":{"description":"Invalid reply_order format"},"403":{"description":"Insufficient scope or not authorized"},"404":{"description":"Message not found"},"422":{"description":"Invalid reply IDs"},"500":{"description":"Failed to update reply order"}}}},"/v1/messages/{message_id}/default_outgoing":{"patch":{"tags":["messages"],"summary":"Set default outgoing","description":"Set or clear the default outgoing child for a message.\n\nRequires `messages.write` scope. Only the message author or their manager can change it.\nThe id must be a current outgoing reply or stitch child. Null clears the default.\nThis is independent of `reply_order`.","operationId":"update_message_default_outgoing_v1_messages__message_id__default_outgoing_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDefaultOutgoingRequest"}}}},"responses":{"200":{"description":"Updated message with new default outgoing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageOutput"}}}},"403":{"description":"Insufficient scope or not authorized"},"404":{"description":"Message not found"},"422":{"description":"Invalid default outgoing id"},"500":{"description":"Failed to update default outgoing"}}}},"/v1/messages/batch":{"delete":{"tags":["messages"],"summary":"Batch delete messages","description":"Delete multiple messages.\nOnly the author or their manager can delete a message.","operationId":"batch_delete_messages_v1_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/BatchDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/{message_id}/tree-ids":{"get":{"tags":["messages"],"summary":"Get tree message IDs","description":"Get all message IDs in the conversation tree containing the given message.","operationId":"get_tree_ids_v1_messages__message_id__tree_ids_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TreeIdsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/public/batch":{"patch":{"tags":["messages"],"summary":"Batch set message visibility","description":"Set public flag for multiple messages.","operationId":"batch_set_public_v1_messages_public_batch_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchSetPublicRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchSetPublicResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/{message_id}/ping":{"post":{"tags":["messages"],"summary":"Ping recipients","description":"Explicitly notify recipients of a message.\nUnlike adding recipients, this does not modify the message visibility or edges.\nIt triggers a notification of type 'ping' to the specified users.\n\nBot Policy: Bots are instructed to reply to 'ping' notifications.","operationId":"ping_recipients_v1_messages__message_id__ping_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models":{"get":{"tags":["models"],"summary":"List Models","description":"List available models (bots and their versions).\nFormat is compatible with OpenAI's /v1/models endpoint.","operationId":"list_models_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Models V1 Models Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/channels":{"get":{"tags":["channels"],"summary":"List user's channels","description":"Get all channels the current user is a member of.","operationId":"list_user_channels_v1_channels_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ChannelOutput"},"type":"array","title":"Response List User Channels V1 Channels Get"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["channels"],"summary":"Create channel","description":"Create a new channel. Requires channels.create scope. Creator is added as admin.","operationId":"create_channel_v1_channels_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelCreateRequest"}}},"required":true},"responses":{"201":{"description":"Channel created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelOutput"}}}},"403":{"description":"Insufficient scope (channels.create required)"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/channels/{channel_id}":{"get":{"tags":["channels"],"summary":"Get channel details","description":"Get channel by ID. User must be a member.","operationId":"get_channel_v1_channels__channel_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"responses":{"200":{"description":"Channel details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelOutput"}}}},"403":{"description":"Not a member"},"404":{"description":"Channel not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["channels"],"summary":"Update channel","description":"Update channel metadata. User must be channel admin.","operationId":"update_channel_v1_channels__channel_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelUpdateRequest"}}}},"responses":{"200":{"description":"Channel updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelOutput"}}}},"403":{"description":"Not authorized (admin required)"},"404":{"description":"Channel not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["channels"],"summary":"Delete channel","description":"Delete a channel. User must be channel admin.","operationId":"delete_channel_v1_channels__channel_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"responses":{"204":{"description":"Channel deleted"},"403":{"description":"Not authorized (admin required)"},"404":{"description":"Channel not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/channels/{channel_id}/members":{"get":{"tags":["channels"],"summary":"List channel members","description":"Get all members of a channel. User must be a member.","operationId":"list_channel_members_v1_channels__channel_id__members_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"responses":{"200":{"description":"Channel members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ChannelMemberInfo"},"title":"Response List Channel Members V1 Channels  Channel Id  Members Get"}}}},"403":{"description":"Not a member"},"404":{"description":"Channel not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["channels"],"summary":"Add channel members","description":"Add members to a channel. User must be channel admin.","operationId":"add_channel_members_v1_channels__channel_id__members_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddChannelMembersRequest"}}}},"responses":{"200":{"description":"Members added (check response for failures)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddChannelMembersResponse"}}}},"403":{"description":"Not authorized (admin required)"},"404":{"description":"Channel not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/channels/{channel_id}/members/{user_id}":{"delete":{"tags":["channels"],"summary":"Remove channel member","description":"Remove a member from a channel. User must be admin OR removing themselves.","operationId":"remove_channel_member_v1_channels__channel_id__members__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Not authorized"},"404":{"description":"Channel or member not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/channels/{channel_id}/messages":{"get":{"tags":["channels"],"summary":"List channel messages","description":"Get messages in a channel. User must be a member.","operationId":"list_channel_messages_v1_channels__channel_id__messages_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset","default":0,"title":"Skip"},"description":"Pagination offset"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Page size","default":50,"title":"Limit"},"description":"Page size"}],"responses":{"200":{"description":"Channel messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"403":{"description":"Not a member"},"404":{"description":"Channel not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/channels/batch/add":{"post":{"tags":["channels"],"summary":"Batch add messages to channels","description":"Add multiple messages to multiple channels.","operationId":"batch_add_channels_v1_channels_batch_add_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchAddChannelsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchAddChannelsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/import/cursor":{"post":{"tags":["imports"],"summary":"Import Cursor conversation","description":"Import messages from Cursor IDE or code review sessions.\n\nRequires both `messages.write` and `messages.import.cursor` scopes.\nAllows specifying `content_author` to import multi-party conversations.\nAll imports are logged with user UID and timestamp for audit purposes.","operationId":"import_cursor_conversation_v1_messages_import_cursor_post","requestBody":{"content":{"application/json":{"schema":{"title":"Payload"}}},"required":true},"responses":{"200":{"description":"Import results (check individual items for success/error)","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/MessageCreateResult"},"type":"array","title":"Response Import Cursor Conversation V1 Messages Import Cursor Post"}}}},"400":{"description":"Invalid request body or author validation failed"},"403":{"description":"Insufficient scope"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/import/audio":{"post":{"tags":["imports"],"summary":"Import audio transcription","description":"Import messages from audio transcription with speaker diarization.\n\nRequires both `messages.write` and `messages.import.audio` scopes.\nAllows specifying `content_author` to import multi-speaker conversations.\nAll imports are logged with user UID and timestamp for audit purposes.\n\nExpected payload format:\n- Array of MessageCreateRequest objects with `content_author` for each speaker\n- Each message should include `content` (transcribed text) and `content_author` (speaker UID)\n- Recipients can be specified to control visibility","operationId":"import_audio_transcription_v1_messages_import_audio_post","requestBody":{"content":{"application/json":{"schema":{"title":"Payload"}}},"required":true},"responses":{"200":{"description":"Import results (check individual items for success/error)","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/MessageCreateResult"},"type":"array","title":"Response Import Audio Transcription V1 Messages Import Audio Post"}}}},"400":{"description":"Invalid request body or author validation failed"},"403":{"description":"Insufficient scope"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/messages/import/quote":{"post":{"tags":["imports"],"summary":"Quote/Import message from another platform","description":"Import a message with a custom author display name and link to original source.\nThe actual message author will be the current user, but the display name will be overridden in UI.\n\nThe client may also provide `import_info.original_timestamp` to record when the message was said on the original platform/source, and `import_info.source_platform` (e.g. slack, discord) for display on the imported-message badge.","operationId":"import_quote_v1_messages_import_quote_post","requestBody":{"content":{"application/json":{"schema":{"title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/MessageCreateResult"},"type":"array","title":"Response Import Quote V1 Messages Import Quote Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/users/register":{"post":{"tags":["users"],"summary":"Register a new user","description":"Create a new user account with email and password.\n\nRequired fields:\n- email: Valid email address\n- password: Min 8 characters, must contain letters and numbers\n- user_tag: Username (2-24 chars, letters/numbers/hyphens only)\n- display_name: Display name\n\nReturns an opaque session (`access_token` + HttpOnly `stitch_session` cookie). Sends a welcome message.\n\n**Email Verification:** A verification code is automatically sent to the provided email address.\nUse the `/v1/auth/contacts/email/verify` endpoint with the code to verify your email and unlock full write access.","operationId":"register_user_v1_users_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}},"required":true},"responses":{"200":{"description":"Registration successful, verification email sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Missing required fields or validation failed"},"409":{"description":"User tag already in use"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/login":{"get":{"tags":["users"],"summary":"Verify login","description":"Verify the current opaque session (cookie or Bearer) and return user information.","operationId":"login_user_v1_users_login_get","responses":{"200":{"description":"Session valid, returns user info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Invalid or expired session"}},"security":[{"HTTPBearer":[]}]}},"/v1/users/me":{"get":{"tags":["users"],"summary":"Get current user","description":"Get detailed information about the authenticated user including permissions and endpoint signing status.","operationId":"get_current_user_info_v1_users_me_get","responses":{"200":{"description":"Current user info with permissions","content":{"application/json":{"schema":{}}}},"401":{"description":"Not authenticated"}},"security":[{"HTTPBearer":[]}]},"delete":{"tags":["users"],"summary":"Delete account","description":"Permanently delete the authenticated user's account. This action cannot be undone.","operationId":"delete_own_account_v1_users_me_delete","responses":{"200":{"description":"Account deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAccountResponse"}}}},"500":{"description":"Failed to delete account"}},"security":[{"HTTPBearer":[]}]}},"/v1/users/profile":{"post":{"tags":["users"],"summary":"Update user profile","description":"Update the authenticated user's profile.\n\nSupports updating:\n- display_name, user_tag, bio, font\n- email, phone_number, endpoint (contact methods). A new webhook URL is verified automatically via nonce echo; save still succeeds if verification fails.\n- notify preferences (per contact type)\n- endpoint_signing_secret (webhook HMAC secret)\n- private flag (profile visibility)\n- Bot fields (is_bot, input_modalities, output_modalities, third_party_integrations, context_origin_id)","operationId":"update_user_profile_v1_users_profile_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Profile updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileUpdateResponse"}}}},"400":{"description":"Invalid field values"},"409":{"description":"User tag already in use"},"500":{"description":"Failed to update profile"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/users/unread-total":{"get":{"tags":["users"],"summary":"Get unread count","description":"Get the total number of unread messages for the authenticated user.","operationId":"get_unread_total_v1_users_unread_total_get","responses":{"200":{"description":"Unread count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnreadTotalResponse"}}}},"500":{"description":"Failed to get unread count"}},"security":[{"HTTPBearer":[]}]}},"/v1/users/search":{"get":{"tags":["users"],"summary":"Search users","description":"Search for users by display name, username, or email. Results respect privacy settings.","operationId":"search_users_endpoint_v1_users_search_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Search query (display name, username, or email)","title":"Query"},"description":"Search query (display name, username, or email)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Maximum results to return","default":15,"title":"Limit"},"description":"Maximum results to return"}],"responses":{"200":{"description":"Matching users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSearchResponse"}}}},"500":{"description":"Search failed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/by-tag/{user_tag}":{"get":{"tags":["users"],"summary":"Get user by exact user_tag","description":"Fetch a single user/bot profile by exact user_tag (case-insensitive). Respects privacy/visibility rules.","operationId":"get_user_by_tag_endpoint_v1_users_by_tag__user_tag__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_tag","in":"path","required":true,"schema":{"type":"string","title":"User Tag"}}],"responses":{"200":{"description":"Matching user","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get User By Tag Endpoint V1 Users By Tag  User Tag  Get"}}}},"404":{"description":"User not found or not visible"},"400":{"description":"Invalid user_tag"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/messages/mark-read":{"post":{"tags":["users"],"summary":"Mark messages as read","description":"Mark one or more messages as read for the authenticated user.","operationId":"mark_read_v1_users_messages_mark_read_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkReadRequest","description":"Single message ID or list of IDs"}}},"required":true},"responses":{"200":{"description":"Messages marked as read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkReadResponse"}}}},"400":{"description":"No message IDs provided"},"500":{"description":"Failed to mark messages as read"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/users/messages/mark-all-read":{"post":{"tags":["users"],"summary":"Mark all messages as read","description":"Mark all messages as read for the authenticated user.","operationId":"mark_all_read_v1_users_messages_mark_all_read_post","responses":{"200":{"description":"Messages marked as read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkReadResponse"}}}},"500":{"description":"Failed to mark messages as read"}},"security":[{"HTTPBearer":[]}]}},"/v1/users/messages/{message_id}/mark-unread":{"post":{"tags":["users"],"summary":"Mark message as unread","description":"Mark a specific message as unread for the authenticated user.","operationId":"mark_message_as_unread_v1_users_messages__message_id__mark_unread_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"responses":{"200":{"description":"Message marked as unread","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkUnreadResponse"}}}},"404":{"description":"No receiver edge for this user"},"500":{"description":"Failed to mark message as unread"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/thread-unread-counts":{"post":{"tags":["users"],"summary":"Refresh inbox thread unread badges","description":"Return backend unread_count_in_thread for the given inbox leaf message IDs.","operationId":"get_thread_unread_counts_v1_users_thread_unread_counts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadUnreadCountsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadUnreadCountsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/users/messages/{message_id}/save":{"post":{"tags":["users"],"summary":"Save message","description":"Save a message to the authenticated user's saved messages list.","operationId":"save_message_v1_users_messages__message_id__save_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"responses":{"200":{"description":"Message saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveMessageResponse"}}}},"500":{"description":"Failed to save message"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["users"],"summary":"Unsave message","description":"Remove a message from the authenticated user's saved messages list.","operationId":"unsave_message_v1_users_messages__message_id__save_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"responses":{"200":{"description":"Message unsaved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveMessageResponse"}}}},"500":{"description":"Failed to unsave message"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/saved-messages":{"get":{"tags":["users"],"summary":"Get saved messages","description":"Get the authenticated user's saved messages with pagination.","operationId":"get_saved_messages_v1_users_saved_messages_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of messages to skip","default":0,"title":"Skip"},"description":"Number of messages to skip"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of messages to return","default":15,"title":"Limit"},"description":"Number of messages to return"}],"responses":{"200":{"description":"Paginated saved messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesResponse"}}}},"500":{"description":"Failed to get saved messages"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/managed/users":{"get":{"tags":["managed"],"summary":"List managed users","description":"List managed users for the current manager.\n\nIf operating in a delegated session (acting-as), uses the actor subject as the manager context.","operationId":"list_managed_users_endpoint_v1_managed_users_get","responses":{"200":{"description":"List of managed users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedUsersListResponse"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["managed"],"summary":"Create managed user","description":"Create a new managed user (bot or proxy account).\n\nRequires `messages.write` permission. The new user will be managed by the current user\n(or the acting-as user in delegated sessions).","operationId":"create_managed_user_endpoint_v1_managed_users_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedUserCreateRequest"}}},"required":true},"responses":{"200":{"description":"Managed user created successfully","content":{"application/json":{"schema":{}}}},"400":{"description":"Invalid input (missing fields, invalid user_tag format)"},"403":{"description":"Insufficient scope"},"409":{"description":"User tag already in use"},"500":{"description":"Failed to create managed user"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/managed/users/{uid}":{"delete":{"tags":["managed"],"summary":"Delete managed user","description":"Delete a managed user. Only managers of the user can perform this action.","operationId":"delete_managed_user_endpoint_v1_managed_users__uid__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}}],"responses":{"200":{"description":"Managed user deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteManagedResponse"}}}},"403":{"description":"Insufficient scope or not a manager"},"404":{"description":"User not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/managed/auth/switch":{"post":{"tags":["managed"],"summary":"Switch to managed user","description":"Switch into a managed user via opaque session (browser act-as).\n\nRequires the current manager session as the HttpOnly `stitch_session` cookie.\nMints a delegated opaque session (`actor` = manager, `subject` = managed user),\nsets `stitch_session` to that token, and may set `stitch_mgr_session` as a return backup.","operationId":"managed_switch_v1_managed_auth_switch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedSwitchRequest"}}},"required":true},"responses":{"200":{"description":"Switched to managed user session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Missing managed_uid or session cookie"},"401":{"description":"Invalid session"},"403":{"description":"Insufficient permission or not a manager of the target user"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/managed/auth/delegate":{"post":{"tags":["managed"],"summary":"Delegate to managed user (programmatic)","description":"Mint a delegated opaque session for a managed user (M2M / bots).\n\nUnlike `/auth/switch` (cookie-based browser flow), this endpoint:\n- Accepts `Authorization: Bearer <manager session>` or `x-api-key: <manager API key>`\n- Returns the delegated `st_session_…` token in the response body\n- Does not set cookies\n\nRequirements:\n- Manager has `messages.write`\n- Manager manages the target (`manages` edge)\n- If the manager session was issued by an API key, manager must have `has_api_access=true`\n\nThe session row stores `actor_user_id` = manager and `subject_user_id` = managed user.\nInspect via `GET /v1/auth/session` (`delegated: true`), not by parsing the token.","operationId":"delegate_to_managed_user_v1_managed_auth_delegate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDelegateRequest"}}},"required":true},"responses":{"200":{"description":"Delegated opaque session minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Missing managed_uid"},"403":{"description":"Not a manager or insufficient permission"},"404":{"description":"Managed user not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/managed/auth/sessions/revoke_all":{"post":{"tags":["managed"],"summary":"Revoke all sessions","description":"Revoke opaque sessions for the current principal.\n\nOptionally cascade to delegated sessions where this actor is the manager\n(`include_managed=true`).","operationId":"managed_revoke_all_v1_managed_auth_sessions_revoke_all_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedRevokeRequest"}}}},"responses":{"200":{"description":"Sessions revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedRevokeResponse"}}}},"403":{"description":"Insufficient permission"},"500":{"description":"Failed to revoke"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/managed/auth/return_to_self":{"post":{"tags":["managed"],"summary":"Return to manager session","description":"Exit a delegated (acting-as) session and restore the manager's own session.\n\nUses the manager backup opaque session in the `stitch_mgr_session` cookie\n(set during `/managed/auth/switch` or act-as). Revokes the current delegated\nsession when present, rotates the backup into a fresh manager session, and\nsets `stitch_session`.","operationId":"managed_return_to_self_v1_managed_auth_return_to_self_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReturnToSelfRequest"}}},"required":true},"responses":{"200":{"description":"Restored manager session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Missing manager backup cookie or backup is not a manager session"},"401":{"description":"Invalid manager backup session"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/managed/users/{uid}/managers":{"get":{"tags":["managed"],"summary":"List managers for user","description":"List all managers who can act-as the specified user. Requires being a manager or the user themselves.","operationId":"list_managers_for_managed_v1_managed_users__uid__managers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}}],"responses":{"200":{"description":"List of managers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagersListResponse"}}}},"403":{"description":"Not authorized"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["managed"],"summary":"Add manager to user","description":"Add a manager who can act-as the specified user.\n\nProvide either `manager_uid` or `identifier` (@username or email) to resolve the manager.\nRequires being a manager or the user themselves.","operationId":"add_manager_for_managed_v1_managed_users__uid__managers_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagerRequest"}}}},"responses":{"200":{"description":"Manager added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagerResponse"}}}},"400":{"description":"Missing manager identifier"},"403":{"description":"Not authorized"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/managed/users/{uid}/managers/{manager_uid}":{"delete":{"tags":["managed"],"summary":"Remove manager from user","description":"Remove a manager from the specified user. Requires being a manager or the user themselves.","operationId":"remove_manager_for_managed_v1_managed_users__uid__managers__manager_uid__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}},{"name":"manager_uid","in":"path","required":true,"schema":{"type":"string","title":"Manager Uid"}}],"responses":{"200":{"description":"Manager removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveManagerResponse"}}}},"403":{"description":"Not authorized"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/managed/users/{uid}/convert-to-managed":{"post":{"tags":["managed"],"summary":"Convert user to managed","description":"Convert a regular user to a managed user.\n\nThe caller must be the user themselves or already be a manager of the user.\n\nBody:\n- `manager_uid` (required): The UID of the manager to assign\n- `scopes` (optional): Scopes to set (defaults to \"messages.read messages.write realtime.connect\")","operationId":"convert_user_to_managed_endpoint_v1_managed_users__uid__convert_to_managed_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertToManagedRequest"}}}},"responses":{"200":{"description":"User converted to managed","content":{"application/json":{"schema":{}}}},"400":{"description":"User already managed or cannot be own manager"},"403":{"description":"Not authorized"},"404":{"description":"User or manager not found"},"500":{"description":"Failed to convert user"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/messages/{message_id}/public":{"patch":{"tags":["messages"],"summary":"Set message visibility","description":"Toggle or set the public flag for a single message.\n\nRules:\n- Requires `messages.write` scope\n- Only the message author or their manager can change publicity\n- No admin bypass on public router - admins must use internal router\n- Does not cascade; only updates the specific message\n- Leaves recipients untouched","operationId":"set_message_public_v1_messages__message_id__public_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"message_id","in":"path","required":true,"schema":{"type":"string","title":"Message Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPublicRequest"}}}},"responses":{"200":{"description":"Updated message with new visibility","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageOutput"}}}},"400":{"description":"Invalid body"},"403":{"description":"Insufficient scope or not authorized"},"404":{"description":"Message not found"},"500":{"description":"Failed to update visibility"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/files/upload":{"post":{"tags":["files"],"summary":"Upload file","description":"Upload a single file for use in messages.\n\n    Supported file types:\n    - PDF documents (application/pdf)\n     - Images (jpg, png, gif, webp)\n     - Text files (.txt) and code files (.py)\n     - Audio files (mp3, wav, ogg, flac, aac, m4a)\n     - Videos (mp4, webm, mpeg)\n\n    Maximum file size: 100MB\n\nReturns file metadata with a signed URL for access.","operationId":"upload_file_endpoint_v1_files_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_endpoint_v1_files_upload_post"}}},"required":true},"responses":{"200":{"description":"File uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileMetadata"}}}},"400":{"description":"Invalid file type"},"413":{"description":"File too large (max 100MB)"},"500":{"description":"Upload failed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/users/me/speed-dial":{"get":{"tags":["speed-dial"],"summary":"Get speed dial","description":"Get current user's speed dial list, ordered by position.","operationId":"get_speed_dial_v1_users_me_speed_dial_get","responses":{"200":{"description":"Speed dial list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedDialListResponse"}}}},"401":{"description":"Not authenticated"}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["speed-dial"],"summary":"Add to speed dial","description":"Add a user to the current user's speed dial.","operationId":"add_to_speed_dial_v1_users_me_speed_dial_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddToSpeedDialRequest"}}},"required":true},"responses":{"200":{"description":"User added, returns updated speed dial","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedDialListResponse"}}}},"400":{"description":"Invalid request (self-add, already in list, list full)"},"401":{"description":"Not authenticated"},"404":{"description":"Target user not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/users/me/speed-dial/{uid}":{"delete":{"tags":["speed-dial"],"summary":"Remove from speed dial","description":"Remove a user from the current user's speed dial.","operationId":"remove_from_speed_dial_v1_users_me_speed_dial__uid__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}}],"responses":{"200":{"description":"User removed, returns updated speed dial","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedDialListResponse"}}}},"401":{"description":"Not authenticated"},"404":{"description":"User not in speed dial"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/me/speed-dial/reorder":{"put":{"tags":["speed-dial"],"summary":"Reorder speed dial","description":"Reorder speed dial entries. Must include all current speed dial UIDs.","operationId":"reorder_speed_dial_v1_users_me_speed_dial_reorder_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReorderSpeedDialRequest"}}},"required":true},"responses":{"200":{"description":"Speed dial reordered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedDialListResponse"}}}},"400":{"description":"Invalid UID list (duplicates, missing, or unknown UIDs)"},"401":{"description":"Not authenticated"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/users/me/speed-dial/{uid}/tier":{"patch":{"tags":["speed-dial"],"summary":"Update speed dial tier","description":"Update the tier of a speed dial entry (1=main, 2=expanded).","operationId":"update_speed_dial_tier_v1_users_me_speed_dial__uid__tier_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTierRequest"}}}},"responses":{"200":{"description":"Tier updated, returns updated speed dial","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedDialListResponse"}}}},"400":{"description":"Invalid tier value"},"401":{"description":"Not authenticated"},"404":{"description":"User not in speed dial"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/users/me/speed-dial/check/{uid}":{"get":{"tags":["speed-dial"],"summary":"Check if user is in speed dial","description":"Check if a specific user is in the current user's speed dial.","operationId":"check_speed_dial_v1_users_me_speed_dial_check__uid__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string","title":"Uid"}}],"responses":{"200":{"description":"Returns whether user is in speed dial","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Check Speed Dial V1 Users Me Speed Dial Check  Uid  Get"}}}},"401":{"description":"Not authenticated"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/health":{"get":{"tags":["status"],"summary":"Health check","description":"Check if the API is healthy and responding. No authentication required.","operationId":"public_health_v1_health_get","responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/.well-known/jwks.json":{"get":{"summary":"Jwks Root","operationId":"jwks_root__well_known_jwks_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AddChannelMembersRequest":{"properties":{"user_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"User Ids","description":"List of user UIDs to add"}},"type":"object","required":["user_ids"],"title":"AddChannelMembersRequest","description":"Request to add members to a channel."},"AddChannelMembersResponse":{"properties":{"added":{"items":{"type":"string"},"type":"array","title":"Added","description":"Successfully added user IDs"},"failed":{"items":{"type":"string"},"type":"array","title":"Failed","description":"Failed user IDs"}},"type":"object","title":"AddChannelMembersResponse","description":"Response for adding members to a channel."},"AddManagerRequest":{"properties":{"manager_uid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manager Uid","description":"UID of manager to add"},"identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Identifier","description":"@user_tag or email to resolve"}},"type":"object","title":"AddManagerRequest","description":"Request body for adding a manager."},"AddManagerResponse":{"properties":{"created":{"type":"boolean","title":"Created","description":"Whether manager was added"}},"type":"object","required":["created"],"title":"AddManagerResponse","description":"Response for adding a manager."},"AddRecipientsRequest":{"properties":{"message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message Id","description":"Single message ID"},"message_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Message Ids","description":"Multiple message IDs"},"recipients":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/RecipientInput"}]},"type":"array","title":"Recipients","description":"Recipients to add. String format defaults to notify=true. Use object format for per-recipient control. Dict objects will be automatically coerced to RecipientInput by Pydantic."},"propagation":{"anyOf":[{"$ref":"#/components/schemas/PropagationStrategy"},{"type":"null"}],"description":"DEPRECATED: Use explicit message_ids instead. Propagation strategy for adding recipients to related messages. Defaults to NONE (no propagation)."}},"type":"object","required":["recipients"],"title":"AddRecipientsRequest","description":"Request body for adding recipients.\n\nRecipients can be specified as:\n- String: \"alice\" or \"@alice\" or \"uid:abc123\" (defaults to public=true, notify=true)\n- RecipientInput object: {\"user_tag\": \"alice\", \"public\": true, \"notify\": false}\n\nNote: Dict objects will be automatically coerced to RecipientInput by Pydantic."},"AddRecipientsResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"results":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Results","description":"Per-message results"}},"type":"object","title":"AddRecipientsResponse","description":"Response for adding recipients."},"AddToSpeedDialRequest":{"properties":{"uid":{"type":"string","title":"Uid","description":"UID of user to add to speed dial"},"position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Position","description":"Position in speed dial (defaults to end)"},"tier":{"type":"integer","title":"Tier","description":"Tier level: 1=main, 2=expanded","default":1}},"type":"object","required":["uid"],"title":"AddToSpeedDialRequest","description":"Request to add a user to speed dial."},"AuthorInfo":{"properties":{"uid":{"type":"string","title":"Uid","description":"User UID"},"user_tag":{"type":"string","title":"User Tag","description":"User tag (handle)"},"display_name":{"type":"string","title":"Display Name","description":"Display name"},"is_bot":{"type":"boolean","title":"Is Bot","description":"Whether author is a bot","default":false},"available_versions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Available Versions","description":"Available versions for bot routing"},"bot_version_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Version Id","description":"Resolved bot version used to generate this message"}},"type":"object","required":["uid","user_tag","display_name"],"title":"AuthorInfo","description":"Normalized author information."},"BatchAddChannelsRequest":{"properties":{"message_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Message Ids","description":"List of message IDs to update"},"channel_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Channel Ids","description":"List of channel IDs to add"}},"type":"object","required":["message_ids","channel_ids"],"title":"BatchAddChannelsRequest","description":"Request body for batch adding channels."},"BatchAddChannelsResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"updated_count":{"type":"integer","title":"Updated Count","description":"Number of messages updated"},"failed_count":{"type":"integer","title":"Failed Count","description":"Number of messages failed"},"errors":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Errors","description":"List of errors per message"}},"type":"object","required":["updated_count","failed_count"],"title":"BatchAddChannelsResponse","description":"Response for batch channel addition."},"BatchDeleteRequest":{"properties":{"message_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Message Ids","description":"List of message IDs to delete"}},"type":"object","required":["message_ids"],"title":"BatchDeleteRequest","description":"Request body for batch deleting messages."},"BatchDeleteResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"deleted_count":{"type":"integer","title":"Deleted Count","description":"Number of messages deleted"},"failed_count":{"type":"integer","title":"Failed Count","description":"Number of messages failed"},"errors":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Errors","description":"List of errors per message"}},"type":"object","required":["deleted_count","failed_count"],"title":"BatchDeleteResponse","description":"Response for batch delete operation."},"BatchSetPublicRequest":{"properties":{"message_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Message Ids","description":"List of message IDs to update"},"public":{"type":"boolean","title":"Public","description":"New public status"}},"type":"object","required":["message_ids","public"],"title":"BatchSetPublicRequest","description":"Request body for batch setting public flag."},"BatchSetPublicResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"updated_count":{"type":"integer","title":"Updated Count","description":"Number of messages updated"},"failed_count":{"type":"integer","title":"Failed Count","description":"Number of messages failed"},"errors":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Errors","description":"List of errors per message"}},"type":"object","required":["updated_count","failed_count"],"title":"BatchSetPublicResponse","description":"Response for batch public update."},"Body_upload_file_endpoint_v1_files_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"File to upload"}},"type":"object","required":["file"],"title":"Body_upload_file_endpoint_v1_files_upload_post"},"ChallengeResponse":{"properties":{"created":{"type":"boolean","title":"Created","description":"Whether challenge was created","default":true},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"ISO timestamp when challenge expires"}},"type":"object","title":"ChallengeResponse","description":"Response for challenge creation."},"ChannelCreateRequest":{"properties":{"display_name":{"type":"string","maxLength":32,"minLength":1,"title":"Display Name","description":"Channel display name"},"description":{"type":"string","maxLength":512,"minLength":1,"title":"Description","description":"Channel description"}},"type":"object","required":["display_name","description"],"title":"ChannelCreateRequest","description":"Request model for creating a channel."},"ChannelMemberInfo":{"properties":{"uid":{"type":"string","title":"Uid","description":"User UID"},"display_name":{"type":"string","title":"Display Name","description":"User display name"},"user_tag":{"type":"string","title":"User Tag","description":"User tag (handle)"},"is_admin":{"type":"boolean","title":"Is Admin","description":"Whether user is channel admin","default":false},"joined_at":{"type":"string","format":"date-time","title":"Joined At","description":"When user joined the channel"},"added_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Added By","description":"UID of user who added this member"},"added_by_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Added By Tag","description":"User tag of user who added this member"}},"type":"object","required":["uid","display_name","user_tag","joined_at"],"title":"ChannelMemberInfo","description":"Channel member information."},"ChannelOutput":{"properties":{"id":{"type":"string","title":"Id","description":"Channel ID (_key)"},"display_name":{"type":"string","maxLength":32,"title":"Display Name","description":"Channel display name"},"description":{"type":"string","maxLength":512,"title":"Description","description":"Channel description"},"member_count":{"type":"integer","title":"Member Count","description":"Number of members in channel","default":0},"is_admin":{"type":"boolean","title":"Is Admin","description":"Whether current user is channel admin","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When channel was created"}},"type":"object","required":["id","display_name","description","created_at"],"title":"ChannelOutput","description":"Full channel output model for API responses."},"ChannelUpdateRequest":{"properties":{"display_name":{"anyOf":[{"type":"string","maxLength":32,"minLength":1},{"type":"null"}],"title":"Display Name","description":"Channel display name"},"description":{"anyOf":[{"type":"string","maxLength":512,"minLength":0},{"type":"null"}],"title":"Description","description":"Channel description (empty string clears it)"}},"type":"object","title":"ChannelUpdateRequest","description":"Request model for updating a channel."},"Contact":{"properties":{"type":{"type":"string","enum":["email","phone","endpoint"],"title":"Type"},"value":{"type":"string","title":"Value"},"verified":{"type":"boolean","title":"Verified","default":false},"notify":{"type":"boolean","title":"Notify","default":false},"verified_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verified At"}},"type":"object","required":["type","value"],"title":"Contact","description":"Canonical contact method for a user."},"ConvertToManagedRequest":{"properties":{"manager_uid":{"type":"string","title":"Manager Uid","description":"UID of manager to assign"},"permissions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Permissions","description":"Principal grant to set"},"scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scopes","description":"Deprecated alias for permissions"}},"type":"object","required":["manager_uid"],"title":"ConvertToManagedRequest","description":"Request body for converting user to managed."},"DeleteAccountResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether deletion succeeded","default":true}},"type":"object","title":"DeleteAccountResponse","description":"Response for account deletion."},"DeleteManagedResponse":{"properties":{"deleted":{"type":"boolean","title":"Deleted","description":"Whether deletion succeeded","default":true}},"type":"object","title":"DeleteManagedResponse","description":"Response for deleting a managed user."},"EndpointVerifyRequest":{"properties":{"endpoint":{"type":"string","title":"Endpoint","description":"Webhook endpoint URL to verify"},"timeout_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timeout Ms","description":"Request timeout in milliseconds","default":5000},"insecure_tls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Insecure Tls","description":"Allow insecure TLS (dev only)","default":false}},"type":"object","required":["endpoint"],"title":"EndpointVerifyRequest","description":"Request body for endpoint verification."},"FileMetadata":{"properties":{"filename":{"type":"string","title":"Filename","description":"Original filename"},"content_type":{"type":"string","title":"Content Type","description":"MIME type"},"size":{"type":"integer","title":"Size","description":"File size in bytes"},"url":{"type":"string","title":"Url","description":"Signed URL for access"},"gcs_path":{"type":"string","title":"Gcs Path","description":"Cloud storage path"}},"type":"object","required":["filename","content_type","size","url","gcs_path"],"title":"FileMetadata","description":"Metadata for an uploaded file."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status","description":"Service status","default":"healthy"},"timestamp":{"type":"string","title":"Timestamp","description":"ISO timestamp"},"version":{"type":"string","title":"Version","description":"API version"}},"type":"object","required":["timestamp","version"],"title":"HealthResponse","description":"Health check response."},"ImportInfo":{"properties":{"display_name":{"type":"string","title":"Display Name","description":"Original author's display name"},"original_timestamp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Timestamp","description":"When the message was said on the original platform/source (user-provided, stored for display)"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url","description":"Link to original source"},"source_platform":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Source Platform","description":"Original platform name for display (e.g. slack, discord, imessage)"},"importer_uid":{"type":"string","title":"Importer Uid","description":"UID of user who imported this"},"importer_user_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Importer User Tag","description":"User tag of importer"}},"type":"object","required":["display_name","importer_uid"],"title":"ImportInfo","description":"Metadata for imported/quoted messages."},"LinkResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"message":{"type":"string","title":"Message","description":"Status message"}},"type":"object","required":["message"],"title":"LinkResponse","description":"Response for link operations."},"LogoutResponse":{"properties":{"logged_out":{"type":"boolean","title":"Logged Out","description":"Whether logout succeeded","default":true}},"type":"object","title":"LogoutResponse","description":"Response for logout."},"ManagedDelegateRequest":{"properties":{"managed_uid":{"type":"string","title":"Managed Uid","description":"UID of managed user to delegate to"},"requested_permissions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Permissions","description":"Space-delimited permissions to request"},"requested_scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Scopes","description":"Deprecated alias for requested_permissions","default":"messages.read messages.write"},"aud":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aud","description":"Legacy audience field; ignored"}},"type":"object","required":["managed_uid"],"title":"ManagedDelegateRequest","description":"Request body for programmatic delegation (service-to-service)."},"ManagedRevokeRequest":{"properties":{"include_managed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Managed","description":"Also revoke delegated sessions where this actor is the manager","default":false}},"type":"object","title":"ManagedRevokeRequest","description":"Request body for revoking sessions."},"ManagedRevokeResponse":{"properties":{"revoked":{"type":"boolean","title":"Revoked","description":"Whether revocation succeeded","default":true},"own_count":{"type":"integer","title":"Own Count","description":"Opaque sessions revoked for the current principal","default":0},"cascade_count":{"type":"integer","title":"Cascade Count","description":"Delegated (act-as) sessions revoked for this manager","default":0}},"type":"object","title":"ManagedRevokeResponse","description":"Response for session revocation."},"ManagedSwitchRequest":{"properties":{"managed_uid":{"type":"string","title":"Managed Uid","description":"UID of managed user to switch to"},"requested_permissions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Permissions","description":"Space-delimited permissions to request"},"requested_scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Scopes","description":"Deprecated alias for requested_permissions","default":"messages.read messages.write realtime.connect"},"aud":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aud","description":"Legacy audience field; ignored"},"device_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Id","description":"Optional device identifier"}},"type":"object","required":["managed_uid"],"title":"ManagedSwitchRequest","description":"Request body for switching to managed user session."},"ManagedUserCreateRequest":{"properties":{"display_name":{"type":"string","minLength":1,"title":"Display Name","description":"Display name"},"user_tag":{"type":"string","maxLength":24,"minLength":2,"title":"User Tag","description":"Username"},"endpoints":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Endpoints","description":"Webhook endpoint URLs"},"permissions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Permissions","description":"Principal grant (space-delimited)"},"scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scopes","description":"Deprecated alias for permissions"},"private":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Private","description":"Whether profile is private","default":false},"is_bot":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Bot","description":"Whether this is a bot account","default":false}},"type":"object","required":["display_name","user_tag"],"title":"ManagedUserCreateRequest","description":"Request body for creating a managed user."},"ManagedUsersListResponse":{"properties":{"users":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Users","description":"Managed users"}},"type":"object","title":"ManagedUsersListResponse","description":"Response for listing managed users."},"ManagersListResponse":{"properties":{"managers":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Managers","description":"Manager users"}},"type":"object","title":"ManagersListResponse","description":"Response for listing managers."},"MarkReadRequest":{"properties":{"message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message Id","description":"Single message ID"},"message_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Message Ids","description":"Multiple message IDs"}},"type":"object","title":"MarkReadRequest","description":"Request body for marking messages as read."},"MarkReadResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"updated_count":{"type":"integer","title":"Updated Count","description":"Number of messages marked as read","default":0},"already_read_count":{"type":"integer","title":"Already Read Count","description":"Number of messages already read","default":0},"total_processed":{"type":"integer","title":"Total Processed","description":"Total messages processed","default":0},"unread_total":{"type":"integer","title":"Unread Total","description":"Unread messages remaining for this user","default":0}},"type":"object","title":"MarkReadResponse","description":"Response for marking messages as read."},"MarkUnreadResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"is_read":{"type":"boolean","title":"Is Read","description":"Read state after the operation","default":false},"unread_total":{"type":"integer","title":"Unread Total","description":"Unread messages remaining for this user","default":0}},"type":"object","title":"MarkUnreadResponse","description":"Response for marking a message as unread."},"MessageCreateResult":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"anyOf":[{"$ref":"#/components/schemas/MessageOutput"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["success"],"title":"MessageCreateResult","description":"Per-message creation result for unified create endpoint"},"MessageOutput":{"properties":{"id":{"type":"string","title":"Id"},"type":{"type":"string","title":"Type","description":"Type of message: message, function_invocation, or function_response","default":"message"},"subject":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject"},"content":{"title":"Content","description":"Message text, or the function dictionary when type is function_invocation or function_response"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"author":{"$ref":"#/components/schemas/AuthorInfo"},"recipients":{"items":{"$ref":"#/components/schemas/RecipientInfo"},"type":"array","title":"Recipients"},"public":{"type":"boolean","title":"Public"},"parent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Id"},"child_ids":{"items":{"type":"string"},"type":"array","title":"Child Ids","default":[]},"stitch_parent_ids":{"items":{"type":"string"},"type":"array","title":"Stitch Parent Ids","description":"Incoming stitch links (link parents)"},"stitch_child_ids":{"items":{"type":"string"},"type":"array","title":"Stitch Child Ids","description":"Outgoing stitch links (link children)"},"reply_order":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Reply Order","description":"Partial order of outgoing child IDs (replies and stitches)"},"default_outgoing":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Outgoing","description":"Default outgoing child ID, independent of reply_order"},"files":{"items":{"$ref":"#/components/schemas/FileMetadata"},"type":"array","title":"Files","description":"Attached files"},"tags":{"items":{"anyOf":[{"$ref":"#/components/schemas/Tag"},{"additionalProperties":true,"type":"object"}]},"type":"array","title":"Tags"},"channels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Channels","description":"Channels this message belongs to"},"is_read":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Read"},"is_saved":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Saved"},"unread_count_in_thread":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unread Count In Thread"},"import_info":{"anyOf":[{"$ref":"#/components/schemas/ImportInfo"},{"type":"null"}],"description":"Import metadata"},"extras":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Extras","description":"Extra metadata"},"font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font","description":"Allowlisted font preset snapshotted from the author at create time"}},"type":"object","required":["id","content","timestamp","author","public"],"title":"MessageOutput","description":"Standardized message response model for API/Webhooks/WebSocket."},"PaginatedMessagesResponse":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/MessageOutput"},"type":"array","title":"Messages"},"total":{"type":"integer","title":"Total"},"skip":{"type":"integer","title":"Skip"},"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["messages","total","skip","limit","has_more"],"title":"PaginatedMessagesResponse","description":"Paginated response for messages"},"PasswordChangeRequest":{"properties":{"current_password":{"type":"string","title":"Current Password","description":"Current password for verification"},"new_password":{"type":"string","minLength":8,"title":"New Password","description":"New password (min 8 chars, must contain letters and numbers)"}},"type":"object","required":["current_password","new_password"],"title":"PasswordChangeRequest","description":"Request body for password change."},"PasswordResetBody":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email address"},"user_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Tag","description":"Username"},"code":{"type":"string","title":"Code","description":"6-digit verification code"},"new_password":{"type":"string","minLength":8,"title":"New Password","description":"New password"},"aud":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aud","description":"Legacy audience field; ignored"},"device_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Id","description":"Optional device identifier stored on the new session"}},"type":"object","required":["code","new_password"],"title":"PasswordResetBody","description":"Request body for completing password reset."},"PasswordResetRequestBody":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email address"},"user_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Tag","description":"Username (to disambiguate multiple accounts)"}},"type":"object","title":"PasswordResetRequestBody","description":"Request body for initiating password reset."},"PingRequest":{"properties":{"recipients":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/RecipientInput"}]},"type":"array","title":"Recipients","description":"Recipients to ping. String format defaults to notify=true."},"context":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Context","description":"Explicit context for bot history (ancestors)"}},"type":"object","required":["recipients"],"title":"PingRequest","description":"Request body for pinging recipients."},"PingResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"notification_count":{"type":"integer","title":"Notification Count","description":"Number of notifications sent","default":0}},"type":"object","title":"PingResponse","description":"Response for ping operation."},"ProfileResponse":{"properties":{"uid":{"type":"string","title":"Uid","description":"User ID"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email address"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name","description":"Display name"},"user_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Tag","description":"Username"},"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number","description":"Phone number"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio","description":"User bio"},"font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font","description":"Allowlisted message font preset id"},"is_bot":{"type":"boolean","title":"Is Bot","description":"Whether this is a bot account","default":false},"input_modalities":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Input Modalities","description":"Bot input modalities"},"output_modalities":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Modalities","description":"Bot output modalities"},"third_party_integrations":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Third Party Integrations","description":"Bot third-party integrations"},"available_versions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Available Versions","description":"Available versions for bot routing"},"context_origin_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context Origin Id","description":"Message id that starts this bot's context, omitted when the viewer cannot see it"}},"type":"object","required":["uid"],"title":"ProfileResponse","description":"Response for profile operations."},"ProfileUpdateRequest":{"properties":{"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name","description":"Display name"},"user_tag":{"anyOf":[{"type":"string","maxLength":24,"minLength":2},{"type":"null"}],"title":"User Tag","description":"Username"},"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number","description":"Phone number"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Email address"},"endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endpoint","description":"Webhook endpoint URL"},"notify":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Notify","description":"Notification preferences per contact type"},"endpoint_signing_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endpoint Signing Secret","description":"Webhook signing secret"},"private":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Private","description":"Whether profile is private"},"bio":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Bio","description":"User bio"},"font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font","description":"Allowlisted message font preset id"},"is_bot":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Bot","description":"Whether this is a bot account"},"input_modalities":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Input Modalities","description":"Bot input modalities"},"output_modalities":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Modalities","description":"Bot output modalities"},"third_party_integrations":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Third Party Integrations","description":"Bot third-party integrations"},"available_versions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Available Versions","description":"Available versions for bot routing"},"context_origin_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context Origin Id","description":"Message id that starts this bot's context"}},"type":"object","title":"ProfileUpdateRequest","description":"Request body for profile updates."},"ProfileUpdateResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether update succeeded","default":true},"profile":{"$ref":"#/components/schemas/ProfileResponse","description":"Updated profile"},"endpoint_verified":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Endpoint Verified","description":"Present when an endpoint URL was saved; true if nonce-echo verification succeeded"}},"type":"object","required":["profile"],"title":"ProfileUpdateResponse","description":"Response for profile update."},"PropagationStrategy":{"properties":{"strategy":{"type":"string","title":"Strategy","description":"Propagation strategy: NONE, ANCESTORS, or TREE","default":"NONE"}},"type":"object","title":"PropagationStrategy","description":"Propagation strategy for adding recipients to message trees.\n\nControls how recipients are added across related messages:\n- \"NONE\": Only add to the specified message(s) (default)\n- \"ANCESTORS\": Add to visible ancestors (stops when parent is not visible)\n- \"TREE\": Add to entire conversation tree (ancestors + descendants + siblings)"},"RecipientInfo":{"properties":{"uid":{"type":"string","title":"Uid","description":"User UID"},"user_tag":{"type":"string","title":"User Tag","description":"User tag (handle)"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name","description":"Display name"},"is_bot":{"type":"boolean","title":"Is Bot","description":"Whether recipient is a bot","default":false},"available_versions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Available Versions","description":"Available versions for bot routing"},"is_public":{"type":"boolean","title":"Is Public","description":"Whether recipient is visible (CC) or hidden (BCC)","default":true},"added_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Added By","description":"UID of user who added this recipient"},"added_by_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Added By Tag","description":"User tag of user who added this recipient"}},"type":"object","required":["uid","user_tag"],"title":"RecipientInfo","description":"Normalized recipient information (OUTPUT model).\n\nThis is the stored/response shape for recipients.\nNote: Does NOT include `notify` flag - that is input-only (see RecipientInput)."},"RecipientInput":{"properties":{"user_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Tag","description":"User tag (with or without @)"},"uid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uid","description":"User UID (or 'uid:...' format)"},"public":{"type":"boolean","title":"Public","description":"CC (true) vs BCC (false)","default":true},"notify":{"type":"boolean","title":"Notify","description":"Send notification to this recipient (input-only, not stored)","default":true},"bot_version_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Version Id","description":"Bot version ID (input-only)"}},"type":"object","title":"RecipientInput","description":"Input model for a single recipient.\n\nThe `notify` flag controls whether a notification is sent to this recipient.\nIt is INPUT-ONLY and is NOT stored on the recipient edge.\n\nAccepts either:\n- user_tag: \"@alice\" or \"alice\" \n- uid: \"uid:abc123\" or just the UID"},"RegisterRequest":{"properties":{"email":{"type":"string","title":"Email","description":"User email address"},"password":{"type":"string","minLength":8,"title":"Password","description":"Password (min 8 chars, must contain letters and numbers)"},"user_tag":{"type":"string","maxLength":24,"minLength":2,"title":"User Tag","description":"Username (letters, numbers, hyphens only)"},"display_name":{"type":"string","minLength":1,"title":"Display Name","description":"Display name"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone","description":"Phone number (E.164 format)"},"endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endpoint","description":"Webhook endpoint URL"},"notify":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Notify","description":"Notification preferences per contact type"},"private":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Private","description":"Whether profile is private","default":false}},"type":"object","required":["email","password","user_tag","display_name"],"title":"RegisterRequest","description":"Request body for user registration."},"RemoveManagerResponse":{"properties":{"removed":{"type":"boolean","title":"Removed","description":"Whether manager was removed"}},"type":"object","required":["removed"],"title":"RemoveManagerResponse","description":"Response for removing a manager."},"RemoveRecipientRequest":{"properties":{"message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message Id","description":"Single message ID"},"message_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Message Ids","description":"Multiple message IDs"},"recipient_uid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Uid","description":"UID of recipient to remove"},"recipient":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient","description":"Recipient identifier (tag or UID) to remove"},"propagate_to_descendants":{"type":"boolean","title":"Propagate To Descendants","description":"Also remove recipient from descendants","default":false}},"type":"object","title":"RemoveRecipientRequest","description":"Request body for removing a recipient."},"ReorderSpeedDialRequest":{"properties":{"uids":{"items":{"type":"string"},"type":"array","title":"Uids","description":"Ordered list of UIDs"}},"type":"object","required":["uids"],"title":"ReorderSpeedDialRequest","description":"Request to reorder speed dial entries."},"ReturnToSelfRequest":{"properties":{"device_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Id","description":"Optional device identifier"},"requested_permissions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Permissions","description":"Unused on return; manager session permissions come from the backup session"},"requested_scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Scopes","description":"Deprecated alias for requested_permissions"},"aud":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aud","description":"Legacy audience field; ignored"}},"type":"object","title":"ReturnToSelfRequest","description":"Request body for returning to manager session."},"SaveMessageResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether operation succeeded","default":true},"is_saved":{"type":"boolean","title":"Is Saved","description":"Current saved state"}},"type":"object","required":["is_saved"],"title":"SaveMessageResponse","description":"Response for save/unsave message."},"SetPublicRequest":{"properties":{"public":{"type":"boolean","title":"Public","description":"Whether message should be public"}},"type":"object","required":["public"],"title":"SetPublicRequest","description":"Request body for setting message publicity."},"SimilarMessageResponse":{"properties":{"id":{"type":"string","title":"Id"},"type":{"type":"string","title":"Type","description":"Type of message: message, function_invocation, or function_response","default":"message"},"subject":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject"},"content":{"title":"Content","description":"Message text, or the function dictionary when type is function_invocation or function_response"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"author":{"$ref":"#/components/schemas/AuthorInfo"},"recipients":{"items":{"$ref":"#/components/schemas/RecipientInfo"},"type":"array","title":"Recipients"},"public":{"type":"boolean","title":"Public"},"parent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Id"},"child_ids":{"items":{"type":"string"},"type":"array","title":"Child Ids","default":[]},"stitch_parent_ids":{"items":{"type":"string"},"type":"array","title":"Stitch Parent Ids","description":"Incoming stitch links (link parents)"},"stitch_child_ids":{"items":{"type":"string"},"type":"array","title":"Stitch Child Ids","description":"Outgoing stitch links (link children)"},"reply_order":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Reply Order","description":"Partial order of outgoing child IDs (replies and stitches)"},"default_outgoing":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Outgoing","description":"Default outgoing child ID, independent of reply_order"},"files":{"items":{"$ref":"#/components/schemas/FileMetadata"},"type":"array","title":"Files","description":"Attached files"},"tags":{"items":{"anyOf":[{"$ref":"#/components/schemas/Tag"},{"additionalProperties":true,"type":"object"}]},"type":"array","title":"Tags"},"channels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Channels","description":"Channels this message belongs to"},"is_read":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Read"},"is_saved":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Saved"},"unread_count_in_thread":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unread Count In Thread"},"import_info":{"anyOf":[{"$ref":"#/components/schemas/ImportInfo"},{"type":"null"}],"description":"Import metadata"},"extras":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Extras","description":"Extra metadata"},"font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font","description":"Allowlisted font preset snapshotted from the author at create time"},"score":{"type":"number","title":"Score","description":"Similarity score"}},"type":"object","required":["id","content","timestamp","author","public","score"],"title":"SimilarMessageResponse","description":"Message response with similarity score."},"SpeedDialListResponse":{"properties":{"users":{"items":{"$ref":"#/components/schemas/SpeedDialUser"},"type":"array","title":"Users"}},"type":"object","required":["users"],"title":"SpeedDialListResponse","description":"Response containing the speed dial list."},"SpeedDialUser":{"properties":{"uid":{"type":"string","title":"Uid"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"user_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Tag"},"is_bot":{"type":"boolean","title":"Is Bot","default":false},"available_versions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Available Versions"},"position":{"type":"integer","title":"Position"},"tier":{"type":"integer","title":"Tier","default":1},"added_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Added At"}},"type":"object","required":["uid","position"],"title":"SpeedDialUser","description":"A user in the speed dial list."},"Tag":{"properties":{"name":{"type":"string","title":"Name","description":"Tag name (normalized: lowercase, ^[a-z0-9-]+$)"},"created_at":{"type":"string","title":"Created At","description":"ISO timestamp when tag was added"},"added_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Added By","description":"UID of user who added the tag"},"added_by_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Added By Tag","description":"user_tag of who added it"}},"type":"object","required":["name","created_at"],"title":"Tag","description":"Tag with metadata"},"ThreadUnreadCountItem":{"properties":{"id":{"type":"string","title":"Id"},"unread_count_in_thread":{"type":"integer","title":"Unread Count In Thread"}},"type":"object","required":["id","unread_count_in_thread"],"title":"ThreadUnreadCountItem"},"ThreadUnreadCountsRequest":{"properties":{"message_ids":{"items":{"type":"string"},"type":"array","title":"Message Ids","description":"Inbox leaf message IDs"}},"type":"object","required":["message_ids"],"title":"ThreadUnreadCountsRequest","description":"Inbox leaf ids whose backend thread badges should be refreshed."},"ThreadUnreadCountsResponse":{"properties":{"counts":{"items":{"$ref":"#/components/schemas/ThreadUnreadCountItem"},"type":"array","title":"Counts"}},"type":"object","title":"ThreadUnreadCountsResponse"},"TokenRequest":{"properties":{"requested_permissions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Permissions","description":"Space-delimited permissions to request (capped by credential and principal grant)"},"requested_scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Scopes","description":"Deprecated alias for requested_permissions"},"aud":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aud","description":"Legacy audience field; ignored (sessions are public-v1)"},"cnf":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cnf","description":"Legacy DPoP field; ignored"},"act":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Act","description":"Legacy JWT actor claim; ignored — use act-as / managed delegate"},"device_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Id","description":"Optional device identifier stored on the session"}},"type":"object","title":"TokenRequest","description":"Request body for API key → opaque session exchange."},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token","description":"Opaque session token (`st_session_{id}.{secret}`); send as Bearer or rely on stitch_session cookie"},"token_type":{"type":"string","title":"Token Type","description":"Token type (always 'Bearer')","default":"Bearer"},"expires_in":{"type":"integer","title":"Expires In","description":"Session lifetime in seconds (STITCH_SESSION_TTL; default 30 days)","default":2592000},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope","description":"Granted permissions when returned (space-delimited); prefer GET /auth/session"},"email_verification_sent":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Email Verification Sent","description":"True if email verification code was sent (registration only)"}},"type":"object","required":["access_token"],"title":"TokenResponse","description":"OAuth2-shaped response carrying an opaque session token."},"TraversalResponse":{"properties":{"origin":{"$ref":"#/components/schemas/MessageOutput"},"messages":{"items":{"$ref":"#/components/schemas/MessageOutput"},"type":"array","title":"Messages"}},"type":"object","required":["origin","messages"],"title":"TraversalResponse","description":"Unified traversal response containing the origin message and a list of related messages."},"TreeIdsResponse":{"properties":{"message_ids":{"items":{"type":"string"},"type":"array","title":"Message Ids","description":"List of message IDs in the tree"},"count":{"type":"integer","title":"Count","description":"Total number of messages found"}},"type":"object","required":["message_ids","count"],"title":"TreeIdsResponse","description":"Response for tree ID resolution."},"UnreadTotalResponse":{"properties":{"unread_total":{"type":"integer","title":"Unread Total","description":"Total unread messages"}},"type":"object","required":["unread_total"],"title":"UnreadTotalResponse","description":"Response for unread message count."},"UpdateChannelsRequest":{"properties":{"channel_ids":{"items":{"type":"string"},"type":"array","title":"Channel Ids","description":"List of channel IDs to set for the message"}},"type":"object","required":["channel_ids"],"title":"UpdateChannelsRequest","description":"Request model for updating message channels."},"UpdateChannelsResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"channels":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Channels"}},"type":"object","required":["success"],"title":"UpdateChannelsResponse","description":"Response model for updating message channels."},"UpdateDefaultOutgoingRequest":{"properties":{"default_outgoing":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Outgoing","description":"Outgoing child ID to use as the default, or null to clear"}},"type":"object","title":"UpdateDefaultOutgoingRequest","description":"Request body for setting or clearing the default outgoing child."},"UpdateReplyOrderRequest":{"properties":{"reply_order":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Reply Order","description":"Partial order of outgoing child IDs (replies and stitches), or null to clear"}},"type":"object","title":"UpdateReplyOrderRequest","description":"Request body for updating reply order."},"UpdateSubjectRequest":{"properties":{"subject":{"type":"string","maxLength":72,"minLength":1,"title":"Subject","description":"Subject text (max 72 characters)"}},"type":"object","required":["subject"],"title":"UpdateSubjectRequest","description":"Request body for adding a subject to a message."},"UpdateTagsRequest":{"properties":{"message_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Message Ids","description":"Multiple message IDs for batch update"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"New tags to set (replaces existing)"}},"type":"object","required":["tags"],"title":"UpdateTagsRequest","description":"Request body for updating message tags."},"UpdateTierRequest":{"properties":{"tier":{"type":"integer","title":"Tier","description":"Tier level: 1=main, 2=expanded"}},"type":"object","required":["tier"],"title":"UpdateTierRequest","description":"Request to update a speed dial entry's tier."},"User":{"properties":{"uid":{"type":"string","title":"Uid"},"contacts":{"anyOf":[{"items":{"$ref":"#/components/schemas/Contact"},"type":"array"},{"type":"null"}],"title":"Contacts"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"user_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Tag"},"scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scopes","default":""},"permissions":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Permissions"},"is_managed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Managed","default":false},"private":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Private","default":false},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio"},"font":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font"},"is_bot":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Bot","default":false},"input_modalities":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Input Modalities"},"output_modalities":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Modalities"},"third_party_integrations":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Third Party Integrations"},"available_versions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Available Versions"},"context_origin_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Context Origin Id"},"has_api_access":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Api Access","default":false},"aud":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aud"}},"type":"object","required":["uid"],"title":"User","description":"Full User model returned on auth.\nThis model contains all user data and is used for:\n- Current authenticated user\n- User management by admins\n- Authentication and permissions\n\nNote: The uid is stored as _key in ArangoDB and mapped to this field"},"UserSearchResponse":{"properties":{"users":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Users","description":"Matching users"}},"type":"object","title":"UserSearchResponse","description":"Response for user search."},"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"},"VerificationResponse":{"properties":{"verified":{"type":"boolean","title":"Verified","description":"Whether verification succeeded"}},"type":"object","required":["verified"],"title":"VerificationResponse","description":"Generic verification response."}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}},"tags":[{"name":"auth","description":"Authentication and session management"},{"name":"messages","description":"Message creation, reading, and traversal"},{"name":"models","description":"Available AI models and bot versions"},{"name":"enrichment","description":"Message enrichment: tags, recipients, and links"},{"name":"users","description":"User profile and preferences"},{"name":"files","description":"File uploads for messages"},{"name":"managed","description":"Managed (bot/proxy) user accounts"},{"name":"channels","description":"Channel management and message-channel linking"},{"name":"imports","description":"Import messages from external sources"},{"name":"speed-dial","description":"User speed dial (quick-access contacts)"},{"name":"admin","description":"Admin-only metrics and observability"},{"name":"default","description":"JWKS root"},{"name":"status","description":"Health and status endpoints"}]}