openapi: 3.1.0
info:
  title: Telbox API
  description: "The **Telbox API** is the HTTP + WebSocket surface behind Telbox — a voice-first,\nAI-native,\
    \ end-to-end-encrypted communication platform.\n\n* **Base URL:** `https://api.telbox.ai`\n* **Versioning:**\
    \ every endpoint is namespaced under `/v1`.\n* **Auth:** `Authorization: Bearer <access_token>` (JWT).\
    \ See the\n  *Authentication* guide for the phone-OTP bootstrap and token refresh.\n* **Transport\
    \ security:** message and call payloads are end-to-end encrypted;\n  the server stores ciphertext\
    \ only. AI features decrypt server-side inside an\n  isolated worker.\n"
  version: 0.1.1
  termsOfService: https://telbox.ai/terms
  contact:
    name: Telbox Developer Support
    email: developers@telbox.ai
  license:
    name: Proprietary
paths:
  /v1/healthz:
    get:
      tags:
      - health
      summary: Healthz
      description: "Health probe with optional dependency checks.\n\nContract:\n\n* ``GET /healthz?quick=true``\
        \ — returns 200 immediately as long as\n  the FastAPI process is running. Use this for load-balancer\n\
        \  liveness probes; an unhealthy dep should not cause the LB to\n  restart the container.\n\n\
        * ``GET /healthz`` (default) — checks Postgres, Redis, vLLM and\n  the AI worker fleet's liveness.\
        \ Returns 200 if every component\n  is green, 503 if any is down. The body always carries the\n\
        \  per-component verdict so dashboards can graph which dep was\n  degraded.\n\nEach probe has\
        \ its own timeout so a hung dep can't tie up the\nhealth endpoint forever. The probes run concurrently\
        \ — total\nlatency is the slowest single check, not their sum."
      operationId: healthz_v1_healthz_get
      parameters:
      - name: quick
        in: query
        required: false
        schema:
          type: boolean
          description: Skip dependency probes. Used by load-balancer liveness checks that only care if
            the process is alive.
          default: false
          title: Quick
        description: Skip dependency probes. Used by load-balancer liveness checks that only care if the
          process is alive.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Healthz V1 Healthz Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /v1/diagnostics/understand-test:
    post:
      tags:
      - health
      summary: Understand Test
      description: 'Run the understander against an arbitrary transcript and return

        BOTH the raw LLM content and the parsed primary_action / tasks.


        Lets us probe Gemma''s actual output for a given transcript without

        needing to send a real voice note + wait for transcription. The

        smoking-gun question is: when we feed Gemma "Remind me to book a

        flight," does its raw JSON say kind=reminder or kind=none? Until we

        see the raw bytes we''re guessing.


        Dev/staging only — auth-gated and 404''d in prod (see

        ``_require_dev_diagnostics``).'
      operationId: understand_test_v1_diagnostics_understand_test_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Understand Test V1 Diagnostics Understand Test Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/diagnostics/vision-test:
    post:
      tags:
      - health
      summary: Vision Test
      description: 'Smoke-test the multimodal pipeline. Sends a tiny PNG to

        ``_describe_image`` so we can verify Gemma 4''s vision path is

        actually wired through vLLM (chat-completions image_url block) and

        answering. Returns the caption (truncated) and the elapsed time.


        Dev/staging only — auth-gated and 404''d in prod (see

        ``_require_dev_diagnostics``). The previous "no auth, no DB writes"

        contract was wrong: it let any attacker burn GPU on

        attacker-controlled images and read raw model output.'
      operationId: vision_test_v1_diagnostics_vision_test_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
                title: Response Vision Test V1 Diagnostics Vision Test Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/diagnostics/ai-features:
    get:
      tags:
      - health
      summary: Ai Features
      description: 'Snapshot of which AI-pipeline features are currently active.


        Reads the same env knobs the runtime reads, so iOS Settings can

        show the user what''s actually wired without us inventing a per-

        user preferences table. Read-only: flipping these is operator-

        level (env on spark), not user-level.'
      operationId: ai_features_v1_diagnostics_ai_features_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                additionalProperties: true
                type: object
                title: Response Ai Features V1 Diagnostics Ai Features Get
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/diagnostics/schema-version:
    get:
      tags:
      - health
      summary: Schema Version
      description: 'Return the alembic schema version the API is running against.


        Used by the iOS app at launch to detect a deploy that shipped new

        code without applying its migrations — that mismatch was the single

        most common cause of post-deploy "Couldn''t load your inbox" 500s

        in the early ops period. The client compares this against an

        expected revision baked at build time and warns the developer

        rather than silently 500-ing on every authenticated route.'
      operationId: schema_version_v1_diagnostics_schema_version_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                additionalProperties:
                  anyOf:
                  - type: string
                  - type: 'null'
                type: object
                title: Response Schema Version V1 Diagnostics Schema Version Get
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/readyz:
    get:
      tags:
      - health
      summary: Readyz
      description: "Readiness probe. Returns 503 if any critical dep is unreachable.\n\nPhase 3.5: today's\
        \ checks — Postgres (``SELECT 1``) and storage\nbackend (``exists(\"__readyz_probe__\")``). The\
        \ storage check hits\nthe configured backend (local fs or S3) without writing data;\nfailure means\
        \ the orchestrator should drain this instance.\n\nReserved for future:\n* Redis ``PING`` (Phase\
        \ 3 — real Redis client).\n* Outbox lag, computed against\n  ``max(now - outbox_events.created_at)\
        \ where picked_at IS NULL``\n  (Phase 3.1).\n\nEach check has its own timeout so a hung dep can't\
        \ tie up the\nreadiness probe forever — load balancers expect a response in <1s."
      operationId: readyz_v1_readyz_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                additionalProperties: true
                type: object
                title: Response Readyz V1 Readyz Get
      security: []
  /v1/auth/sign-up:
    post:
      tags:
      - auth
      summary: Sign Up
      description: 'Email-password sign-up. Per-IP rate-limited (5/hour) to block

        enumeration + DoS — the previous decorator-less version let an

        attacker hammer this endpoint to enumerate registered emails or

        swamp the workspace-creation path. The phone/start endpoint already

        has a similar gate; sign-up was the missing leg.'
      operationId: sign_up_v1_auth_sign_up_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SignUpInput'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignUpOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'
      security: []
  /v1/auth/sign-in:
    post:
      tags:
      - auth
      summary: Sign In
      operationId: sign_in_v1_auth_sign_in_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SignInInput'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignInOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /v1/auth/phone/start:
    post:
      tags:
      - auth
      summary: Phone Start
      description: 'Begin a phone-OTP sign-in. Either generates a code locally + dispatches

        via OTPSender (log/messages-api), or delegates to Twilio Verify. Rate-limited

        server-side regardless of mode (resend throttle + hourly cap).


        Phase 2.8 — per-phone budget on top of the per-IP global limit.

        SlowAPI''s 10/hour gates by IP, which an attacker rotating IPs

        bypasses; the per-phone token bucket adds a cost the attacker can''t

        rotate around.'
      operationId: phone_start_v1_auth_phone_start_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PhoneStartInput'
        required: true
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PhoneStartOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'
      security: []
  /v1/auth/phone/verify:
    post:
      tags:
      - auth
      summary: Phone Verify
      description: 'Verify the OTP, register the device, return tokens — atomic.


        Why one endpoint and not three: the caller has no user_id when it

        starts. Splitting this into separate /verify + /devices/register +

        /sign-in calls would require a temporary "anonymous device" path on

        the device-register endpoint or a one-time bootstrap token. Cleaner

        to do it as a single transaction here.'
      operationId: phone_verify_v1_auth_phone_verify_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PhoneVerifyInput'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PhoneVerifyOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'
      security: []
  /v1/auth/refresh:
    post:
      tags:
      - auth
      summary: Refresh
      operationId: refresh_v1_auth_refresh_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefreshInput'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefreshOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /v1/devices/register:
    post:
      tags:
      - devices
      summary: Register
      description: 'Register an *additional* device for the calling user.


        The bootstrap path — first-ever device for a user that doesn''t exist

        yet — is handled atomically by ``POST /v1/auth/phone/verify``, which

        creates the user, registers their device, and returns tokens in one

        call (see auth.py ``phone_verify``). This endpoint exists for the

        case where an authenticated user adds a second device (e.g. a tablet

        or a desktop client) — and so it requires the caller''s JWT.


        The historical "anonymous registration" mode allowed any client to

        POST a `user_id` and create a device for that user, which let any

        network observer poison another user''s recipient set. Authenticated

        + ``body.user_id == caller.user_id`` removes that vector.


        BIPA geo gate (premium-tier, 2026-05-18): when the client supplies

        a ``voice_identity_pub_b64``, callers in blocked regions (default

        ``US-IL``) are refused with 403 ``voice_identity_signing_geo_blocked``.

        Voice biometric enrollment in Illinois requires BIPA-compliant

        written opt-in flow which is not yet built. See

        :mod:`telbox.modules.identity.bipa_gate`.'
      operationId: register_v1_devices_register_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterDeviceInput'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegisterDeviceOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/devices/push-token:
    post:
      tags:
      - devices
      summary: Update Push Token
      description: Register or rotate the APNs/FCM push token for the calling device.
      operationId: update_push_token_v1_devices_push_token_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePushTokenInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdatePushTokenOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/devices/voip-token:
    post:
      tags:
      - devices
      summary: Update Voip Push Token
      description: 'Register or rotate the device''s PushKit (VoIP) token.


        Parallel to ``/v1/devices/push-token`` (regular APNs); we keep the

        two tokens in separate columns because PushKit is a distinct

        channel with its own cert. The regular APNs token still wakes

        foregrounded apps for messages; the VoIP token is reserved for

        call invites where the iOS contract requires PushKit + CallKit.


        Idempotent on no-change so a re-launch of the app doesn''t bump

        updated_at when nothing rotated.'
      operationId: update_voip_push_token_v1_devices_voip_token_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateVoIPPushTokenInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdatePushTokenOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/devices/wavelink-key:
    post:
      tags:
      - devices
      summary: Update Wavelink Key
      description: 'Publish or rotate the device''s WaveLink Noise static pubkey.


        Closes the cross-network handshake bug where the WS-relayed

        pubkey exchange races a WS reconnect window. After this lands,

        POST /v1/calls returns the callee''s pubkey directly so the

        initiator starts the Noise handshake without the round-trip.'
      operationId: update_wavelink_key_v1_devices_wavelink_key_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWaveLinkKeyInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateWaveLinkKeyOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/devices/wavelink-endpoint:
    post:
      tags:
      - devices
      summary: Update Wavelink Endpoint
      description: 'Publish the device''s STUN-discovered WAN endpoint hint.


        Idempotent: if (host, port) match the stored value AND

        ``last_wan_seen_at`` is within 60 s, returns ``updated=false``

        without writing. This lets iOS publish aggressively (every 30 s

        during a call) without pounding the DB.


        Best-effort — a network failure here doesn''t block anything;

        a missing hint just means the call falls back to the legacy

        WS endpoint exchange (pre-B-3 behaviour).'
      operationId: update_wavelink_endpoint_v1_devices_wavelink_endpoint_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWaveLinkEndpointInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateWaveLinkEndpointOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me:
    get:
      tags:
      - me
      summary: Me
      operationId: me_v1_me_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MeResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    patch:
      tags:
      - me
      summary: Update Me
      description: 'Update the caller''s profile. Currently `display_name`,

        `preferred_language`, and morning_brief subscription are accepted;

        each may be omitted to leave that field alone.'
      operationId: update_me_v1_me_patch
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMeRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateMeResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - settings
      summary: Delete Me
      description: "Hard-delete the user and everything they own.\n\nCascade behavior:\n  - Workspaces\
        \ *owned* by the user are deleted; the FK cascade on\n    Workspace.id removes threads, messages,\
        \ memory, tasks, people,\n    message recipients, etc.\n  - Workspaces the user is a *member*\
        \ of (but doesn't own) are NOT\n    deleted; we just remove the WorkspaceMember row, leaving the\n\
        \    workspace and its other members intact.\n  - The User row, all Devices, all Tasks assigned\
        \ to them, all\n    ThreadMember rows, all AuditEntry rows referencing them — go.\n  - Voice clones\
        \ (biometric) + their object-storage audio are deleted\n    explicitly in step 0 — ``voice_clones``\
        \ has no FK to ``users`` so\n    nothing cascades to it.\n  - The user's avatar + message-media\
        \ object-storage blobs are deleted\n    best-effort (step 0b). Other E2E-ciphertext blobs (call\
        \ audio,\n    thread/PA avatars, anon-drops) await a storage delete-prefix\n    sweeper (#80).\n\
        \nFor Apple compliance: this is genuinely deletion, not a soft-delete or\n\"we'll get to it eventually.\"\
        \ Audit-log preservation requirements (if\nany) need to be added later as a separate retention\
        \ policy."
      operationId: delete_me_v1_me_delete
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeleteMeInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteMeOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/avatar:
    post:
      tags:
      - me
      summary: Upload Avatar
      description: 'Replace the caller''s avatar. Body is the raw image bytes (PNG or

        JPEG); content-type validated client-side.'
      operationId: upload_avatar_v1_me_avatar_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Upload Avatar V1 Me Avatar Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - me
      summary: Get My Avatar
      description: 'Convenience for the iOS app: fetch the caller''s avatar without

        knowing their own user_id (it''s stored in keychain, but this

        saves a round-trip).'
      operationId: get_my_avatar_v1_me_avatar_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/identity:
    post:
      tags:
      - me
      summary: Set User Identity
      description: 'Set the caller''s long-lived user identity public key (Ed25519, 32 bytes).


        Idempotent on first set: the same key may be re-uploaded any number of

        times (matches the iCloud-Keychain-sync flow where two devices generate

        the value once and re-publish it on each launch).


        A DIFFERENT key counts as identity rotation. Today we accept it

        silently — the iOS client will eventually surface a "Will rotated their

        account identity" prompt to peers. Servers cannot distinguish "lost

        keychain, legitimate reset" from "attacker swap"; that judgment is the

        user''s, made out-of-band.'
      operationId: set_user_identity_v1_me_identity_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserIdentityRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserIdentityResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/devices:
    get:
      tags:
      - me
      summary: List My Devices
      description: 'List every active (non-revoked) device for the caller.


        Same shape as ``MeResponse.devices`` but addressable on its own so

        the iOS My Devices screen can refresh independently of the broader

        /me bootstrap.'
      operationId: list_my_devices_v1_me_devices_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/devices/{device_id}:
    delete:
      tags:
      - me
      summary: Revoke My Device
      description: 'Revoke one of the caller''s devices.


        Refuses to revoke the device the caller is signed in on right now —

        that would lock them out. Use ``/sign-out-all`` if the goal is "log

        me out everywhere"; that path explicitly preserves the current

        session and rotates the refresh-token family.


        Revoked devices are excluded from message envelope recipients

        going forward, and any existing WebSocket session bound to the

        device should be closed by the transport layer on next ping.'
      operationId: revoke_my_device_v1_me_devices__device_id__delete
      parameters:
      - name: device_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Device Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RevokeDeviceResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/devices/sign-out-all:
    post:
      tags:
      - me
      summary: Sign Out All Other Devices
      description: 'Revoke every device for the caller *except* the one this request

        is coming from.


        Use case: user thinks an old phone or tablet is compromised and

        just wants a clean slate without enumerating each one. The current

        device stays signed in and keeps working.


        A future revision will also rotate the refresh-token family so any

        leaked refresh tokens become useless. Today refresh tokens are

        JWT-stateless so this is a no-op there; the device revocation is

        what carries the security guarantee.'
      operationId: sign_out_all_other_devices_v1_me_devices_sign_out_all_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignOutAllResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/consent:
    post:
      tags:
      - me
      summary: Set Consent
      description: 'Capture or revoke an onboarding consent.


        Each field is independent. Passing ``true`` stamps the current UTC

        timestamp; passing ``false`` clears the timestamp (revocation).

        Omitting a field leaves it unchanged.


        Audit: each consent state change emits a structured log line so the

        audit chain has a permanent record of the user''s affirmations and

        revocations. The DB row itself is the timestamp source of truth.'
      operationId: set_consent_v1_me_consent_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConsentRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConsentResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/badge:
    get:
      tags:
      - me
      summary: My Badge
      description: "Return the caller's total unread count across every thread.\n\nCounts messages that:\n\
        \n  - belong to a thread the caller is an active member of\n  - are not deleted\n  - were sent\
        \ by someone else (not the caller's own messages)\n  - are newer than the caller's ``last_read_at``\
        \ on that thread\n    (or any peer message at all when last_read_at is NULL —\n    a never-opened\
        \ thread is fully unread)\n  - are not server-side-hidden via ``message_hides`` for this user\n\
        \nCapped at 999 — anything higher renders as \"999+\" badge."
      operationId: my_badge_v1_me_badge_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadgeResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/users/lookup:
    get:
      tags:
      - users
      summary: Lookup User
      description: 'Look up a user by email OR phone (E.164). Phone takes precedence

        when both are supplied. The "Add by phone" affordance in iOS uses

        this with phone — necessary because phone-OTP signups have no email.'
      operationId: lookup_user_v1_users_lookup_get
      parameters:
      - name: email
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Email
      - name: phone
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Phone
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserLookupResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/users/by-ids:
    post:
      tags:
      - users
      summary: Users By Ids
      description: 'Batch userID → display-name resolver.


        Used by the iOS search-results UI to render "Sarah: <snippet>" on

        hits from group threads, where the per-message ``sender_user_id``

        is known locally (it''s on the FTS row) but the name isn''t cached

        anywhere on the client. A batched POST beats N×GET round trips

        and keeps the URL away from query-string length limits when a

        page of search results spans 30+ distinct senders.


        Auth: any signed-in caller may resolve any visible (non-deleted)

        user''s display_name. Same posture as ``/lookup`` — display_name

        is not sensitive enough to gate behind shared-thread membership

        in v0.1; tightening this is a follow-up if abuse shows up in

        audit.'
      operationId: users_by_ids_v1_users_by_ids_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UsersByIDsRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UsersByIDsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/users/{user_id}/devices:
    get:
      tags:
      - users
      summary: Get User Devices
      description: 'Return ALL of a user''s devices, including revoked ones.


        Stage 1 of the identity-continuity work (see docs/protocols/IDENTITY.md):

        recipients need historical identity keys to verify older messages from

        a sender device that has since been retired. The wire view exposes

        `is_active` so senders'' clients won''t ship NEW envelopes to revoked

        recipients while still letting older bubbles render verified.'
      operationId: get_user_devices_v1_users__user_id__devices_get
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PeerDevicesResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/users/{user_id}/avatar:
    get:
      tags:
      - users
      summary: Get User Avatar
      description: 'Stream a user''s avatar bytes. Authenticated callers only —

        matches the visibility model of display_name + phone (already

        user-discoverable). Returns 404 when the user has no avatar set

        (or is soft-deleted).'
      operationId: get_user_avatar_v1_users__user_id__avatar_get
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/pin:
    put:
      tags:
      - favorites
      summary: Pin Thread
      operationId: pin_thread_v1_threads__thread_id__pin_put
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - favorites
      summary: Unpin Thread
      description: 'Idempotent: a missing pin returns 204 silently.'
      operationId: unpin_thread_v1_threads__thread_id__pin_delete
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/pinned:
    get:
      tags:
      - favorites
      summary: List Pinned Threads
      operationId: list_pinned_threads_v1_threads_pinned_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PinnedThreadView'
                title: Response List Pinned Threads V1 Threads Pinned Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/star:
    put:
      tags:
      - favorites
      summary: Star Message
      operationId: star_message_v1_messages__message_id__star_put
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - favorites
      summary: Unstar Message
      description: 'Idempotent: missing star = 204 silently.'
      operationId: unstar_message_v1_messages__message_id__star_delete
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/starred:
    get:
      tags:
      - favorites
      summary: List Starred Messages
      description: 'Return the caller''s starred messages, newest first.


        Each entry includes ``thread_id`` so the iOS Saved-tab can

        deep-link without a second round-trip. Soft-deleted messages

        are filtered out — a star on a deleted message becomes orphaned

        server-side and gracefully disappears from the list.'
      operationId: list_starred_messages_v1_messages_starred_get
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/StarredMessageView'
                title: Response List Starred Messages V1 Messages Starred Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads:
    post:
      tags:
      - threads
      summary: Create Thread
      operationId: create_thread_v1_threads_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThreadCreateInput'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - threads
      summary: List Threads
      description: 'List threads. When `workspace_id` is omitted, returns every thread the

        caller participates in across every workspace they belong to.


        Pending invitations (where the caller hasn''t yet accepted) are NOT included;

        fetch those via GET /v1/threads/requests.'
      operationId: list_threads_v1_threads_get
      parameters:
      - name: workspace_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Workspace Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ThreadView'
                title: Response List Threads V1 Threads Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/requests:
    get:
      tags:
      - threads
      summary: List Thread Requests
      description: Pending thread invitations addressed to this caller.
      operationId: list_thread_requests_v1_threads_requests_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ThreadRequestView'
                title: Response List Thread Requests V1 Threads Requests Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}:
    get:
      tags:
      - threads
      summary: Get Thread
      description: 'Fetch a single thread by id. Used by the Work tab when the user taps

        a task and we need the destination thread to push into ThreadDetailView.

        Declared *after* the static `/requests` route so FastAPI''s path matcher

        doesn''t try to coerce "requests" into a UUID — that''s how this endpoint

        used to break list_thread_requests.'
      operationId: get_thread_v1_threads__thread_id__get
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    patch:
      tags:
      - threads
      summary: Patch Thread
      description: Update group metadata. MVP supports rename only.
      operationId: patch_thread_v1_threads__thread_id__patch
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThreadPatchInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - threads
      summary: Delete Thread
      description: "Remove the caller from a thread (per-user \"delete from inbox\").\n\nSemantics:\n\
        \  - Sets ``ThreadMember.left_at`` for the caller. The thread vanishes\n    from their inbox and\
        \ is excluded from future direct-thread dedup\n    lookups, so they can later create a fresh thread\
        \ with the same\n    peer if they want.\n  - Other members continue to see the thread; they don't\
        \ lose any\n    history. (This is the \"leave conversation\" semantic, not a\n    global hard-delete\
        \ — appropriate for a messaging app.)\n  - When *every* member has left, soft-delete the Thread\
        \ row so the\n    orphan doesn't sit around in the DB forever.\n\nFor self (Echo) threads we refuse\
        \ — leaving your own voice journal\nhas no useful semantic and would orphan the workspace's echo_thread_id\n\
        pointer."
      operationId: delete_thread_v1_threads__thread_id__delete
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/accept:
    post:
      tags:
      - threads
      summary: Accept Thread Request
      operationId: accept_thread_request_v1_threads__thread_id__accept_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/events:
    get:
      tags:
      - threads
      summary: List Thread Events
      operationId: list_thread_events_v1_threads__thread_id__events_get
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ThreadEventView'
                title: Response List Thread Events V1 Threads  Thread Id  Events Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/members:
    post:
      tags:
      - threads
      summary: Add Thread Members
      operationId: add_thread_members_v1_threads__thread_id__members_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddMembersInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/members/{user_id}:
    delete:
      tags:
      - threads
      summary: Remove Thread Member
      operationId: remove_thread_member_v1_threads__thread_id__members__user_id__delete
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/leave:
    post:
      tags:
      - threads
      summary: Leave Thread
      operationId: leave_thread_v1_threads__thread_id__leave_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/ask:
    post:
      tags:
      - threads
      summary: Thread Ask
      description: 'Ask over ready call-summary transcripts in one thread.


        This is intentionally narrower than `/v1/ask`: it does not search global

        memory, and it only cites call transcript chunks whose summary quality is

        `ready`.'
      operationId: thread_ask_v1_threads__thread_id__ask_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThreadAskRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadAskResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/continuity:
    get:
      tags:
      - threads
      summary: Thread Continuity
      description: "Compute conversation-continuity context for the caller's thread.\n\nLogic:\n    1.\
        \ Verify caller is a thread member.\n    2. Skip self-threads (no peer to remember).\n    3. Find\
        \ peer users (everyone in the thread except caller).\n    4. Resolve peers to Person rows in this\
        \ workspace (by user_id, then\n       by canonical name == display_name).\n    5. Pull the most\
        \ recent 3 memory items for those people across the\n       workspace, regardless of which thread\
        \ they came from.\n    6. Compute hours since the last message in this thread.\n    7. Decide\
        \ `should_show`: peers exist AND silence > 24h AND we have\n       at least one highlight.\n \
        \   8. Compose a one-sentence suggestion the iOS pill renders verbatim."
      operationId: thread_continuity_v1_threads__thread_id__continuity_get
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContinuityResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/mute:
    post:
      tags:
      - threads
      summary: Mute Thread
      description: 'Mute or unmute a thread for the caller. Per-user — muting on one

        device mutes everywhere, since the state lives on `ThreadMember`.'
      operationId: mute_thread_v1_threads__thread_id__mute_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MuteRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MuteResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    put:
      tags:
      - settings
      summary: Mute Thread
      description: Mute alerts for one thread. Idempotent.
      operationId: mute_thread_v1_threads__thread_id__mute_put
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThreadMuteInput'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - settings
      summary: Unmute Thread
      description: 'Drop a thread mute row. Idempotent: 204 on missing row.'
      operationId: unmute_thread_v1_threads__thread_id__mute_delete
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/disappearing:
    post:
      tags:
      - threads
      summary: Set Disappearing
      description: 'Set the disappearing-message window for a thread. Caller must be

        a thread member. The setting is thread-scope (everyone in the thread

        is affected); a per-user opt-out doesn''t make sense for retention.


        Cap at 1 year; null disables. Negative values are rejected.'
      operationId: set_disappearing_v1_threads__thread_id__disappearing_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DisappearingRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DisappearingResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/archive:
    post:
      tags:
      - threads
      summary: Archive Thread
      description: 'Archive a thread — hides it from the inbox. The opposite of unarchive

        is implicit: send a new message and the thread re-surfaces (we leave

        `archived_at` set; the inbox filter is the source of truth).


        NB: archive is workspace-wide, not per-user. If we need per-user archive

        later we''ll move it to ThreadMember; for now the simpler shape ships.'
      operationId: archive_thread_v1_threads__thread_id__archive_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArchiveResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/unarchive:
    post:
      tags:
      - threads
      summary: Unarchive Thread
      operationId: unarchive_thread_v1_threads__thread_id__unarchive_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArchiveResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/decline:
    post:
      tags:
      - threads
      summary: Decline Thread Request
      operationId: decline_thread_request_v1_threads__thread_id__decline_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/send:
    post:
      tags:
      - messages
      summary: Send Message
      operationId: send_message_v1_messages_send_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InboundMessage'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendMessageResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages:
    get:
      tags:
      - messages
      summary: List Messages
      operationId: list_messages_v1_messages_get
      parameters:
      - name: thread_id
        in: query
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: before
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Before
      - name: after
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          description: 'Reconnect catch-up: pass the created_at of the newest message the client already
            has, server returns everything newer. Mutually compatible with `before` for paging the tail.'
          title: After
        description: 'Reconnect catch-up: pass the created_at of the newest message the client already
          has, server returns everything newer. Mutually compatible with `before` for paging the tail.'
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OutboundDelivery'
                title: Response List Messages V1 Messages Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}:
    delete:
      tags:
      - messages
      summary: Delete Message
      description: 'Phase 3.0 — scoped message delete.


        ``?for=everyone`` (default): tombstone the row server-side

        (``message.deleted_at``). The TextChatEngine policy enforces

        that only the original sender can do this. Server then fans

        out a ``message_deleted`` WS event to every thread member''s

        device so their cached copy disappears.


        ``?for=me``: no-op server-side. The client maintains a per-

        device hidden-IDs set in UserDefaults so the message stops

        rendering for that user only — the message stays in the DB

        for everyone else (and survives reinstall via the local

        UserDefaults bag, which iOS persists in the keychain-shadow).


        The endpoint accepts both values so the iOS client can use a

        single API surface; we may later add a server-side per-user

        suppression table for ``for=me`` if cross-device hide becomes

        a requirement.'
      operationId: delete_message_v1_messages__message_id__delete
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: for
        in: query
        required: false
        schema:
          type: string
          default: everyone
          title: For
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - messages
      summary: Get Message
      description: 'Single-message reconciliation endpoint (Bundle 1).


        Returns the freshest server-side view of one message for the iOS

        foreground / WS-reconnect reconciliation paths. Bearer-auth,

        workspace-scoped (caller must be an active member of the message''s

        thread).


        Caching: emits ``ETag: W/"<digest of updated_at>"``. Clients send

        that back in ``If-None-Match``; we return 304 when it matches.

        Cheap for the inbox-foreground burst case where dozens of bubbles

        are re-checked but most haven''t changed.'
      operationId: get_message_v1_messages__message_id__get
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: If-None-Match
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: If-None-Match
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageReconciliationView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/search:
    get:
      tags:
      - messages
      summary: Search Messages
      description: 'Phase 9 — server-side AI-summary search.


        Complement to the iOS local FTS5 search (which only sees what''s

        cached on this device). The server-side path can find content

        on threads the user is a member of but hasn''t opened on this

        device — important for the multi-device case.


        The search ranges over ``messages.ai_payload`` (TIER 1

        summaries only — the field is NULL on Tier 2/3 by design, so the

        end-to-end privacy promise holds: the server can''t search what it

        can''t read). Membership-gated: results are filtered to threads

        the caller is an active member of.


        Snippet extraction is a substring match on ``ai_payload->>summary_short``

        — Postgres FTS could be added in a follow-up but the UI surfaces

        only ~140 chars of preview, so a substring scan over the

        membership-filtered subset is cheap enough.'
      operationId: search_messages_v1_messages_search_get
      parameters:
      - name: q
        in: query
        required: true
        schema:
          type: string
          minLength: 2
          maxLength: 200
          title: Q
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 20
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/MessageSearchHit'
                title: Response Search Messages V1 Messages Search Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/info:
    get:
      tags:
      - messages
      summary: Message Info
      description: 'Per-message delivery + read details, scoped to the caller''s

        visibility.


        Auth: caller must be the sender (only the sender sees the per-

        recipient delivery breakdown — the recipients see only "read"

        state for their own bubble). Non-senders get 403.'
      operationId: message_info_v1_messages__message_id__info_get
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageInfoView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/edit:
    post:
      tags:
      - messages
      summary: Edit Message
      description: "Phase 1c — server-side edit.\n\nThe client provides a fully-formed envelope (same\
        \ shape as\n``POST /send``) plus the URL identifies which message this one\nsupersedes. Server\
        \ enforces:\n\n  - the original sender is the caller (only authors edit);\n  - the source message\
        \ is in the same thread;\n  - the source is not already deleted (you don't edit a tombstone —\n\
        \    send a fresh message instead).\n\nThe new message is committed with ``supersedes_message_id``\
        \ set; the\nold message is tombstoned in the same transaction so peers see one\natomic transition.\
        \ Fan-out:\n\n  - ``message_deleted`` (reason=edited, superseded_by=<new id>) →\n    every recipient\
        \ device of the old message;\n  - ``message.sent`` (the standard send fan-out) → recipient devices\n\
        \    of the new envelope.\n\nThe iOS / Android clients render the new bubble with an \"(edited)\"\
        \nmarker derived from ``supersedes_message_id``."
      operationId: edit_message_v1_messages__message_id__edit_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InboundMessage'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendMessageResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/transcription:
    patch:
      tags:
      - messages
      summary: Edit Message Transcription
      description: "Edit the auto-generated transcript of an audio message.\n\nAuthorization: only the\
        \ original sender (the speaker) may correct\nthe transcript. Other thread members can request\
        \ a re-transcription\nvia ``POST /messages/{id}/retry-ai``.\n\nBehaviour:\n  1. Load the message\
        \ + verify caller is the sender + the row has\n     an ``ai_payload`` (transcript edits don't\
        \ apply to messages\n     that haven't been transcribed yet).\n  2. Snapshot the prior transcript\
        \ into ``message_edits`` with\n     ``kind='transcription'``.\n  3. Update ``ai_payload.transcript.text``\
        \ and clear any cached\n     translation so the next read re-derives it from the corrected\n \
        \    source.\n  4. Fan out ``message.transcript_edited`` over WS so peer devices\n     splice\
        \ the new text into the existing voice bubble without\n     scrolling."
      operationId: edit_message_transcription_v1_messages__message_id__transcription_patch
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TranscriptionEditRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageReconciliationView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/retry-ai:
    post:
      tags:
      - messages
      summary: Retry Ai
      description: 'Re-run the AI pipeline for a message that failed transcription.


        Surfaced on iOS by tapping the orange triangle on a voice bubble. The

        pipeline is idempotent (overwrites ai_payload on success) so re-running

        is safe. We only allow the caller to retry messages they can already

        read — i.e. messages on threads they''re members of.'
      operationId: retry_ai_v1_messages__message_id__retry_ai_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Retry Ai V1 Messages  Message Id  Retry Ai Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/capture-event:
    post:
      tags:
      - messages
      summary: Capture Event
      description: "Record that a recipient screen-captured this message + notify sender.\n\nHonesty about\
        \ what this does:\n  - This is a *behavioral deterrent*, not a security control. The user\n  \
        \  could disable network, the recorder could screenshot before sending,\n    a second phone could\
        \ photograph the screen — none of those leak\n    events generate this event.\n  - But for the\
        \ everyday case (recipient takes a screenshot to share\n    with a friend), it adds friction and\
        \ makes the action visible."
      operationId: capture_event_v1_messages__message_id__capture_event_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CaptureEventRequest'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/mark-read:
    post:
      tags:
      - messages
      summary: Mark Read
      description: 'Mark every message in this thread up to (and including) a target as read

        for the caller''s current device.


        Updates `message_recipients.read_at` (and `delivered_at` if not yet set) so

        senders'' clients can render "heard" / "understood" pills next to their

        messages.'
      operationId: mark_read_v1_messages_mark_read_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MarkReadRequest'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/email-transcript:
    post:
      tags:
      - messages
      summary: Email Call Transcript
      description: 'Email the full call-summary transcript to the caller.


        Membership-gated. The message must be a ``content_type=''call_summary''``

        row in a thread the caller is a member of. Returns 501 when the email

        provider isn''t configured on this deployment — the iOS client maps that

        to a deliberate "Coming soon" hint.'
      operationId: email_call_transcript_v1_messages__message_id__email_transcript_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: boolean
                title: Response Email Call Transcript V1 Messages  Message Id  Email Transcript Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/bulk:
    post:
      tags:
      - messages_bulk
      summary: Bulk Insert Messages
      operationId: bulk_insert_messages_v1_messages_bulk_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkInsertRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkInsertResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/reactions:
    get:
      tags:
      - reactions
      summary: List Reactions
      operationId: list_reactions_v1_messages__message_id__reactions_get
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReactionsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - reactions
      summary: Add Reaction
      description: Add a reaction. Idempotent — re-adding the same emoji is a no-op.
      operationId: add_reaction_v1_messages__message_id__reactions_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
              title: Body
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReactionsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - reactions
      summary: Remove Reaction
      description: 'Remove a reaction by emoji. The query string carries the emoji

        because DELETE bodies are unfriendly across HTTP clients.'
      operationId: remove_reaction_v1_messages__message_id__reactions_delete
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: emoji
        in: query
        required: true
        schema:
          type: string
          title: Emoji
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReactionsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/handoff-events:
    post:
      tags:
      - handoff_events
      summary: Record Event
      description: Record a Hand-off interaction event. Push to sender's devices.
      operationId: record_event_v1_messages__message_id__handoff_events_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HandoffEventIn'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HandoffEventView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - handoff_events
      summary: List Events
      description: 'List events for a message. Only the sender can read the log —

        receipts are private feedback for the user who originally sent the

        Hand-off, not for every thread member.'
      operationId: list_events_v1_messages__message_id__handoff_events_get
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HandoffEventsListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/imports:
    post:
      tags:
      - imports
      summary: Create Import Job
      operationId: create_import_job_v1_imports_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateImportJobRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateImportJobResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - imports
      summary: List Import Jobs
      operationId: list_import_jobs_v1_imports_get
      parameters:
      - name: before
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Before
      - name: after
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: After
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportJobListView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/imports/{job_id}:
    get:
      tags:
      - imports
      summary: Get Import Job
      operationId: get_import_job_v1_imports__job_id__get
      parameters:
      - name: job_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Job Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportJobView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/imports/{job_id}/cancel:
    post:
      tags:
      - imports
      summary: Cancel Import Job
      operationId: cancel_import_job_v1_imports__job_id__cancel_post
      parameters:
      - name: job_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Job Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportJobView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/_debug:
    get:
      tags:
      - tasks
      summary: Debug Tasks
      description: 'Diagnostic snapshot of the caller''s tasks. Temporary.

        VD-PROD-001: dev/staging only.'
      operationId: debug_tasks_v1_tasks__debug_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TasksDebugResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks:
    get:
      tags:
      - tasks
      summary: List Tasks
      description: 'All tasks assigned to the caller, server-side bucketed for the Work tab.


        Open tasks across all workspaces the caller is a member of are returned —

        a unified view, since the user thinks of their work in one place, not

        per-workspace. Completed tasks limited to the last 14 days so the list

        doesn''t grow without bound.'
      operationId: list_tasks_v1_tasks_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TasksGroupedResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - tasks
      summary: Create Task
      description: Manual task creation from the Work tab (+ button).
      operationId: create_task_v1_tasks_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTaskRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/{task_id}/complete:
    post:
      tags:
      - tasks
      summary: Complete Task
      operationId: complete_task_v1_tasks__task_id__complete_post
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/{task_id}/reopen:
    post:
      tags:
      - tasks
      summary: Reopen Task
      operationId: reopen_task_v1_tasks__task_id__reopen_post
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/{task_id}:
    delete:
      tags:
      - tasks
      summary: Dismiss Task
      description: 'Soft-delete: mark dismissed so it''s hidden from lists but the row

        survives for audit/history. We do not hard-delete tasks.


        2026-05-19: an AI-extracted row that the user dismisses is the

        closest analog to "explicit reject" we have, now that the Confirm

        section is collapsed and queue-band rows just auto-create. Feed it

        back into procedural memory so the agent recalibrates over time —

        a swipe-dismiss on a task containing ''maybe later'' phrasing

        should make next week''s similar candidate score lower.


        The feedback signal is intentionally soft: a user might dismiss a

        legit task they already handled, which is a false negative for

        procedural learning. The rule keying (first 6 words of the

        evidence span — see _procedural_rule_from_evidence) keeps the

        signal local enough that one accidental dismiss doesn''t poison

        future extractions.'
      operationId: dismiss_task_v1_tasks__task_id__delete
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    patch:
      tags:
      - tasks
      summary: Update Task
      description: 'Partial update — backs the iOS "Defer all 1 day" bulk action and

        any future inline edits. Only the assignee can mutate; the same

        ownership check used by complete/reopen/dismiss applies here.


        `priority` and `title` are reserved for future use; today the active

        surface is `due_at` (the iOS group-level "Defer all 1 day" walks

        every open task in a sender bucket and PATCHes its `due_at`).'
      operationId: update_task_v1_tasks__task_id__patch
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TaskUpdateRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/promises:
    get:
      tags:
      - tasks
      summary: List Promises
      description: 'Promises segregated by direction.


        Backed by the same `tasks` table — a promise is just a Task with

        `is_promise=True`. Direction is stored assignee-relative at extraction

        time (see pipeline._persist_tasks), so we can filter directly without

        additional joins.'
      operationId: list_promises_v1_tasks_promises_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromisesResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/extraction-blocks:
    get:
      tags:
      - tasks
      summary: List Extraction Blocks
      description: 'Return everyone the caller has muted task-extraction for.


        Drives the iOS Settings → "AI extraction by sender" summary row plus

        the Work-tab hidden-drawer''s resurface affordance. Joins users.id

        so we can render display names without a follow-up round-trip.'
      operationId: list_extraction_blocks_v1_tasks_extraction_blocks_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExtractionBlockListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - tasks
      summary: Toggle Extraction Block
      description: 'Add or remove a per-user mute. Idempotent in both directions —

        re-blocking an already-blocked sender is a no-op, unblocking an

        unmuted one is a no-op. Returns the full updated list so the iOS

        state can replace its cache without a separate GET.'
      operationId: toggle_extraction_block_v1_tasks_extraction_blocks_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExtractionBlockToggleRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExtractionBlockListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/statements:
    get:
      tags:
      - tasks
      summary: List Statements
      description: 'All non-actionable items the agent persisted for this user.


        Capped at the most-recent 100 to keep the surface scannable. Older

        statements remain queryable through the operator console.'
      operationId: list_statements_v1_tasks_statements_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatementsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/pending-confirmation:
    get:
      tags:
      - tasks
      summary: List Pending Confirmation
      description: 'Borderline-confidence rows awaiting the user''s confirm or reject.


        The iOS Work tab also surfaces these inline in the main response

        (``pending_confirmation`` group); this dedicated endpoint is for

        the "everything in one place" view used by power users + the

        notification deep-link target.'
      operationId: list_pending_confirmation_v1_tasks_pending_confirmation_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PendingConfirmationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/{task_id}/confirm:
    post:
      tags:
      - tasks
      summary: Confirm Task
      description: 'User confirms a borderline-confidence task — promote to plain open.


        Side-effect: appends a positive example to procedural memory so

        the next run with similar phrasing routes to auto-create. The

        rule key is deliberately conservative: we tag by the evidence

        span''s first six words so the procedural model groups similar

        utterances without over-generalising.'
      operationId: confirm_task_v1_tasks__task_id__confirm_post
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/{task_id}/reject-as-statement:
    post:
      tags:
      - tasks
      summary: Reject As Statement
      description: 'User rejects a borderline-confidence task — demote to statement.


        Mirrors ``confirm_task`` but writes a negative procedural example.

        The row is NOT deleted — it flips ``is_actionable=False`` and

        ``requires_confirmation=False`` so it joins the Hidden Statements

        surface for review.'
      operationId: reject_as_statement_v1_tasks__task_id__reject_as_statement_post
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/{task_id}/promote:
    post:
      tags:
      - tasks
      summary: Promote Statement
      description: 'User found a wrongly-classified statement in the Hidden Statements

        review surface and wants to convert it back to a real task

        (2026-05-19).


        Mirrors ``confirm_task`` but acts on rows that are

        ``is_actionable=False``. Flips the bool back, clears

        requires_confirmation, restores a confidence floor of 0.7 (the

        agent was wrong; the user''s promote tells us the correct ceiling

        isn''t "statement" territory), and feeds a positive procedural-

        memory example keyed on the evidence span so the next run''s

        similar phrasing scores higher.'
      operationId: promote_statement_v1_tasks__task_id__promote_post
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskMutationResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/{task_id}/reasoning:
    get:
      tags:
      - tasks
      summary: Task Reasoning
      description: 'The "Why did the AI extract this?" affordance on iOS.


        Surfaces the agent''s reasoning, evidence span, suggested actions,

        and the high-level run summary. We deliberately do NOT surface

        the full trace here — that''s an operator-tier view at

        ``/v1/tasks/runs/{id}``. Users get a digestible

        short form.'
      operationId: task_reasoning_v1_tasks__task_id__reasoning_get
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Task Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskReasoningView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/runs/{run_id}:
    get:
      tags:
      - tasks
      summary: Task Creator Run
      description: 'Operator: full trace for one agent run.


        Authorization: caller must be the run''s user_id. We deliberately

        don''t expose other users'' runs even to admins through this route;

        operator console pulls them through its own auth-scoped surface.'
      operationId: task_creator_run_v1_tasks_runs__run_id__get
      parameters:
      - name: run_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Run Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskCreatorRunView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tasks/daily-summary:
    get:
      tags:
      - tasks
      summary: Daily Summary
      description: 'Aggregate agent activity in the last N hours (default 24).


        Drives the iOS Work-tab daily digest one-liner. Cheap: one indexed

        query against ``task_creator_runs`` (`ix_task_creator_runs_user`

        + `ix_task_creator_runs_started`).'
      operationId: daily_summary_v1_tasks_daily_summary_get
      parameters:
      - name: hours
        in: query
        required: false
        schema:
          type: integer
          default: 24
          title: Hours
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DailySummaryView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/actions/_backfill:
    post:
      tags:
      - actions
      summary: Backfill Actions
      description: 'Re-run the AI pipeline for the caller''s recent messages so the

        Work tab fills with actions retroactively. Idempotent — the

        pipeline overwrites prior ai_payload + replaces existing

        suggested_actions for the same message_id.


        Scoped to the caller''s threads; capped at 100 messages so a typo

        or rage-tap can''t kick off a 10k-message reprocess.


        VD-PROD-001: dev/staging only. The iOS client no longer calls

        this on launch; this route belongs in a server-side migration job

        going forward.'
      operationId: backfill_actions_v1_actions__backfill_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BackfillResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/actions/_debug_messages:
    get:
      tags:
      - actions
      summary: Debug Messages
      description: 'Show the AI state of the caller''s recent messages so we can tell

        whether AI is running and what it''s producing. Temporary diagnostic

        for the Work-tab investigation. VD-PROD-001: dev/staging only.'
      operationId: debug_messages_v1_actions__debug_messages_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessagesDebugResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/actions/_debug:
    get:
      tags:
      - actions
      summary: Debug Actions
      description: 'Return diagnostic counts for the caller. Temporary — remove after

        Work-tab fix lands. VD-PROD-001: dev/staging only.'
      operationId: debug_actions_v1_actions__debug_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ActionsDebugResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/actions:
    get:
      tags:
      - actions
      summary: List Actions
      description: "Return open + snoozed-but-due actions for the caller, grouped by urgency.\n\nFilters\
        \ out:\n  • status in (resolved, dismissed)\n  • status=snoozed AND snoozed_until > now (still\
        \ hidden)\n  • expires_at <= now (auto-resolve as stale, then exclude)"
      operationId: list_actions_v1_actions_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ActionsGroupedResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/actions/{action_id}/resolve:
    post:
      tags:
      - actions
      summary: Resolve Action
      description: User acted on the action — mark it resolved.
      operationId: resolve_action_v1_actions__action_id__resolve_post
      parameters:
      - name: action_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Action Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/actions/{action_id}/dismiss:
    post:
      tags:
      - actions
      summary: Dismiss Action
      description: User said "not relevant" — soft-remove.
      operationId: dismiss_action_v1_actions__action_id__dismiss_post
      parameters:
      - name: action_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Action Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/actions/{action_id}/snooze:
    post:
      tags:
      - actions
      summary: Snooze Action
      operationId: snooze_action_v1_actions__action_id__snooze_post
      parameters:
      - name: action_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Action Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SnoozeRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/memory/items:
    get:
      tags:
      - memory
      summary: List Memory Items
      description: 'Return all memory items across the caller''s workspaces, newest first.


        The Memory tab on iOS groups these client-side into Topics (by `kind`),

        People (by `person_id`), and Groups (by source thread). Capped at 500

        so the response stays under a few hundred KB even for power users.

        Echo-derived memories are filtered out (see _exclude_self_thread_clause).'
      operationId: list_memory_items_v1_memory_items_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemoryItemsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - memory
      summary: Create Memory Item
      description: "Manually add a memory item from the iOS app.\n\nTwo source paths from the client:\n\
        \  1. Person detail \"+ Add memory\" — provides ``person_id``; thread\n     and message linkage\
        \ stay null. The item shows up under that\n     contact's facts.\n  2. Thread overflow \"Save\
        \ to memory\" — provides ``thread_id`` (and\n     optionally ``person_id``); we resolve the thread's\
        \ first\n     message as a stand-in source so the deep-link still works.\n\nAuthorization: the\
        \ caller must own the workspace the person/thread\nbelongs to. Echo / self-thread sources are\
        \ still allowed because\nmanual entry is explicit user intent — the privacy filter on\n``list_memory_items``\
        \ only suppresses *AI-extracted* Echo memories."
      operationId: create_memory_item_v1_memory_items_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MemoryItemCreate'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemoryItemView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/people:
    get:
      tags:
      - memory
      summary: List People
      description: 'List people the caller has had real conversations with.


        Default behavior (``include_unmatched=False``) returns only Person

        rows linked to a User who shares a non-self thread with the caller.

        This matches the user''s mental model — "the people I''ve messaged" —

        rather than the previous behavior of listing every name the AI

        extracted from any transcript (which surfaced strangers, prompt

        examples, and one-off mentions in the People tab).


        The earlier behavior is still available via ``include_unmatched=true``

        for debug / admin contexts; the iOS Memory tab uses the default.'
      operationId: list_people_v1_people_get
      parameters:
      - name: include_unmatched
        in: query
        required: false
        schema:
          type: boolean
          description: If true, also return AI-extracted Person rows that are not linked to a real contact
            (debug / data-quality view).
          default: false
          title: Include Unmatched
        description: If true, also return AI-extracted Person rows that are not linked to a real contact
          (debug / data-quality view).
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PeopleListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/people/{person_id}:
    get:
      tags:
      - memory
      summary: Person Detail
      operationId: person_detail_v1_people__person_id__get
      parameters:
      - name: person_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Person Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PersonDetailResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/people/{person_id}/mentions:
    get:
      tags:
      - memory
      summary: Person Call Mentions
      description: "Return calls in which this person was mentioned, newest first.\n\nUsed by:\n  - The\
        \ pre-call AI affordance card (\"Ahmad mentioned in 3 calls\n    this month\") — a single query\
        \ keyed on ``call_id`` rather than\n    joining through messages.\n  - The post-call detail view's\
        \ \"Related calls\" section — same\n    rollup, scoped to a specific person.\n\n``source`` is\
        \ a forward-compat parameter pinned to ``\"calls\"``\ntoday. Future values (e.g. ``\"messages\"\
        ``) can ride on the same\nendpoint without breaking the iOS contract."
      operationId: person_call_mentions_v1_people__person_id__mentions_get
      parameters:
      - name: person_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Person Id
      - name: source
        in: query
        required: false
        schema:
          type: string
          pattern: ^(calls)$
          default: calls
          title: Source
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Since
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PersonCallMentionsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/memory/search:
    get:
      tags:
      - memory
      summary: Memory Search
      description: "Hybrid keyword + semantic search.\n\nStrategy:\n  - Embed the query via nomic-embed-text.\n\
        \  - Postgres returns top-K by cosine distance on `embedding`.\n  - In parallel, do an ILIKE on\
        \ `text` for memories without embeddings\n    (rare — only happens when Ollama was down at write\
        \ time).\n  - Merge results, dedupe, rank by best signal.\n\npgvector's `<=>` is cosine distance;\
        \ smaller is better. We convert to\na similarity score in [0, 1] for the client."
      operationId: memory_search_v1_memory_search_get
      parameters:
      - name: q
        in: query
        required: true
        schema:
          type: string
          minLength: 1
          maxLength: 300
          title: Q
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 20
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemorySearchResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/notification-prefs:
    put:
      tags:
      - settings
      summary: Upsert Notification Prefs
      description: 'Set the caller''s notification privacy mode + optional global mute.


        Idempotent upsert — a row is created on first call and updated on

        subsequent calls.'
      operationId: upsert_notification_prefs_v1_me_notification_prefs_put
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NotificationPrefsInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationPrefsOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - settings
      summary: Get Notification Prefs
      description: 'Return the caller''s current preferences. Defaults shipped when

        no row exists ("full" + no global mute) so the iOS settings screen

        never has to special-case missing rows.'
      operationId: get_notification_prefs_v1_me_notification_prefs_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationPrefsOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/business-sender-mutes:
    put:
      tags:
      - settings
      summary: Mute Business Sender
      description: 'Silence alerts from a verified business / institutional sender

        across every thread. Use the regular block endpoint for full block;

        this is the lighter-weight "I want quiet, not banned" choice.'
      operationId: mute_business_sender_v1_me_business_sender_mutes_put
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BusinessSenderMuteInput'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/business-sender-mutes/{sender_user_id}:
    delete:
      tags:
      - settings
      summary: Unmute Business Sender
      operationId: unmute_business_sender_v1_me_business_sender_mutes__sender_user_id__delete
      parameters:
      - name: sender_user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Sender User Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/workspaces/{workspace_id}/ai-mode:
    patch:
      tags:
      - settings
      summary: Update Workspace Ai Mode
      description: 'Owner / admin can change a workspace''s AI mode.


        Effects: when set to "off", the AI processor is no longer included as a

        recipient on outbound messages from clients that re-fetch /v1/me; the

        pipeline also short-circuits via policy.is_ai_enabled. The Memory tab

        will appear empty for new messages, but historical data is untouched

        (use DELETE /v1/me/memory to wipe).'
      operationId: update_workspace_ai_mode_v1_workspaces__workspace_id__ai_mode_patch
      parameters:
      - name: workspace_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Workspace Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkspaceAIModeInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceAIModeOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/ai:
    patch:
      tags:
      - settings
      summary: Update Thread Ai
      description: 'Per-thread AI off-switch. Any thread member can toggle (no admin

        requirement) — privacy-on-the-individual-conversation is a personal

        preference, not a workspace policy.'
      operationId: update_thread_ai_v1_threads__thread_id__ai_patch
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateThreadAIInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThreadAIOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/memory:
    delete:
      tags:
      - settings
      summary: Wipe Memory
      description: 'Delete every Person and MemoryItem row in workspaces the caller

        OWNS. Crucially scoped to ownership rather than membership so that

        User A''s "wipe my memory" doesn''t also delete User B''s data — the

        DM auto-enrolment in `text_chat.create_thread` makes peers

        workspace MEMBERS, but only the workspace owner gets to wipe.

        Messages and their `ai_payload` JSON are left alone — the AI

        processor''s read of a message is part of the message itself, not

        the user-facing memory store.'
      operationId: wipe_memory_v1_me_memory_delete
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WipeMemoryOutput'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/export:
    get:
      tags:
      - settings
      summary: Export Me
      description: 'JSON dump of the user''s data. iOS shares it via UIActivityViewController

        so the user can save it to Files, AirDrop it to a desktop, etc.'
      operationId: export_me_v1_me_export_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportPayload'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/moderation/report:
    post:
      tags:
      - moderation
      summary: File Report
      description: File a report. Either `message_id` or `reported_user_id` must be set.
      operationId: file_report_v1_moderation_report_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReportRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
  /v1/moderation/block:
    post:
      tags:
      - moderation
      summary: Block User
      description: Block another user. Idempotent — re-blocking is a no-op.
      operationId: block_user_v1_moderation_block_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BlockRequest'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
  /v1/moderation/block/{user_id}:
    delete:
      tags:
      - moderation
      summary: Unblock User
      description: Unblock a user. Idempotent — unblocking a non-blocked user is a no-op.
      operationId: unblock_user_v1_moderation_block__user_id__delete
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/moderation/blocks:
    get:
      tags:
      - moderation
      summary: List Blocks
      description: 'List users the caller has blocked, with their display names so the

        Settings UI can show "Bob — blocked 3 days ago" rows.'
      operationId: list_blocks_v1_moderation_blocks_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BlocksResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/contacts/match:
    post:
      tags:
      - contacts
      summary: Match Contacts
      description: 'Return existing users whose phone hashes appear in the caller''s list.


        Body must include the salt the caller used to derive their hashes; we

        re-derive each existing user''s hash with the same salt to find matches.'
      operationId: match_contacts_v1_contacts_match_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MatchRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatchResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
  /v1/invites/track:
    post:
      tags:
      - contacts
      summary: Track Invite
      description: 'Record (or fetch) a pending invite for the (inviter, phone-hash) pair.


        Idempotent: re-inviting the same phone returns the existing token so the

        client can re-share the same link without creating a new row.'
      operationId: track_invite_v1_invites_track_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InviteTrackRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteTrackResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/invites/mine:
    get:
      tags:
      - contacts
      summary: List My Invites
      description: 'List the caller''s invites with redeemed status.


        Used by a future "Your invites" Settings row — not surfaced in v0 UI yet

        but ready for the rewards mechanic.'
      operationId: list_my_invites_v1_invites_mine_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/media/upload:
    post:
      tags:
      - media
      summary: Upload Blob
      description: Upload an opaque encrypted blob. Returns the object_key + size.
      operationId: upload_blob_v1_media_upload_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  anyOf:
                  - type: string
                  - type: integer
                title: Response Upload Blob V1 Media Upload Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/media/{object_key}:
    get:
      tags:
      - media
      summary: Fetch Blob
      description: "Download an encrypted blob.\n\nAuthorization rule (defense in depth):\n    Allow IF\
        \ the caller is a recipient (via `message_recipients`) of any\n    non-deleted message whose `media_object_key`\
        \ matches the requested key.\n\nThis makes cross-workspace voice notes work — Bob in workspace\
        \ B can fetch\na blob whose key embeds workspace A, *iff* Alice (in A) actually addressed\na message\
        \ containing that blob to one of Bob's devices."
      operationId: fetch_blob_v1_media__object_key__get
      parameters:
      - name: object_key
        in: path
        required: true
        schema:
          type: string
          title: Object Key
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/forensics/verify:
    post:
      tags:
      - forensics
      summary: Verify Watermark
      description: 'Extract the watermark from a (possibly leaked) audio file and look up

        the message it identifies. Caller must be a thread member of the matched

        message''s thread to see the forensic data.'
      operationId: verify_watermark_v1_forensics_verify_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_verify_watermark_v1_forensics_verify_post'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForensicsVerifyResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
  /v1/briefing/today:
    get:
      tags:
      - briefing
      summary: Briefing Today
      description: "Compose the caller's \"what's happening\" dashboard for the last 24h.\n\nSteps:\n\
        \  0. Cache lookup (skipped if ?fresh=true). 3-minute TTL absorbs\n     repeated opens without\
        \ staling out new content.\n  1. List threads the caller is a member of.\n  2. Pull every message\
        \ in those threads from the last 24h. Each\n     open question we extract carries its source message\
        \ + thread\n     IDs so iOS can deep-link to it.\n  3. Fold tasks: open promises (made/received)\
        \ + due-today tasks.\n  4. Return the structured payload — no LLM prose, no\n     hallucinated\
        \ counts."
      operationId: briefing_today_v1_briefing_today_get
      parameters:
      - name: fresh
        in: query
        required: false
        schema:
          type: boolean
          description: Bypass the per-user cache and regenerate.
          default: false
          title: Fresh
        description: Bypass the per-user cache and regenerate.
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BriefingResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/briefing/audio/{token}:
    get:
      tags:
      - briefing
      summary: Briefing Audio
      description: 'Serve a cached brief-audio WAV file identified by an HMAC-signed

        token. Unauthenticated by design — the token IS the auth (signed +

        user-scoped + time-bound). Matches the canonical signed-URL shape

        used by S3 / Cloudflare presigned URLs.


        Returns 403 on bad/expired token; 404 if the cache file is missing

        (the synthesis ran but the file was purged before the iOS pre-fetch

        completed — rare but possible if the cleanup cron beats the fetch).


        Content type is ``audio/wav``: xtts-server returns 22.05kHz PCM

        WAV which iOS AVAudioPlayer plays natively. We chose WAV over m4a

        to avoid bundling ffmpeg in the api container — the size penalty

        is acceptable for a 45s clip (~2 MB vs ~400 KB AAC) and the fetch

        happens once per brief.'
      operationId: briefing_audio_v1_briefing_audio__token__get
      parameters:
      - name: token
        in: path
        required: true
        schema:
          type: string
          title: Token
      responses:
        '200':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/voice-clones:
    get:
      tags:
      - voice_clones
      summary: List Voices
      description: 'All voices the caller can pick from in Settings: built-ins

        first (filtered to the user''s preferred language plus English as

        a universal fallback), then their own clones newest-first.'
      operationId: list_voices_v1_voice_clones_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - voice_clones
      summary: Create Voice Clone
      description: "Accept reference audio, dedupe via Idempotency-Key, enqueue the\ncloning job, return\
        \ 202 with the row's current state.\n\nFlow:\n  1. Validate idempotency-key — must be a UUID.\
        \ Required.\n  2. Look up existing (user_id, idempotency_key) — if hit, return\n     the existing\
        \ row's state verbatim (status from prior call).\n  3. Content-Length pre-check before reading\
        \ body (refuse > 10MB\n     before allocating the memory).\n  4. Validate user + rate-limit (daily\
        \ count + daily bytes +\n     lifetime cap).\n  5. Read body, validate length.\n  6. Stash bytes\
        \ in object storage at workspace-scoped key.\n  7. INSERT the row (catching one-pending-per-user\
        \ collisions).\n  8. Fire the background task. Return 202."
      operationId: create_voice_clone_v1_voice_clones_post
      parameters:
      - name: name
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
      - name: language
        in: query
        required: false
        schema:
          type: string
          default: en
          title: Language
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: Idempotency-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Idempotency-Key
      - name: Content-Length
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Content-Length
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceCloneResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/voice-clones/{clone_id}:
    get:
      tags:
      - voice_clones
      summary: Get Voice Clone
      operationId: get_voice_clone_v1_voice_clones__clone_id__get
      parameters:
      - name: clone_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Clone Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceCloneResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - voice_clones
      summary: Delete Voice Clone
      operationId: delete_voice_clone_v1_voice_clones__clone_id__delete
      parameters:
      - name: clone_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Clone Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/voice-clones/{clone_id}/preview:
    get:
      tags:
      - voice_clones
      summary: Preview Voice Clone
      description: 'Synthesise a short, language-appropriate sample in the user''s

        cloned voice and stream the WAV bytes back. Used by the

        onboarding sheet''s success screen to let the user hear their

        clone before committing.


        Authorization: the clone MUST belong to ``caller.user_id`` AND be

        in ``ready`` status. Returns 404 otherwise so callers can''t probe

        for clone IDs.'
      operationId: preview_voice_clone_v1_voice_clones__clone_id__preview_get
      parameters:
      - name: clone_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Clone Id
      - name: lang
        in: query
        required: false
        schema:
          type: string
          default: en
          title: Lang
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/voice-clones/all:
    delete:
      tags:
      - voice_clones
      summary: Delete All Voice Clones
      description: 'Soft-delete EVERY voice clone owned by the caller AND clear

        their selected_voice pointers. Background cleanup of object-store

        bytes + xtts-server caches is scheduled per row.


        The mid-flight worker (see ``_process_voice_clone_job``) re-checks

        ``deleted_at IS NULL`` between status flips so this is safe to

        invoke while a clone is processing.'
      operationId: delete_all_voice_clones_v1_voice_clones_all_delete
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/ask:
    post:
      tags:
      - ask
      summary: Ask
      operationId: ask_v1_ask_post
      parameters:
      - name: on_agent_event
        in: query
        required: false
        schema:
          title: On Agent Event
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AskRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AskResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/ask/stream:
    post:
      tags:
      - ask
      summary: Ask Stream
      operationId: ask_stream_v1_ask_stream_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AskRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/ai/ask-by-voice:
    post:
      tags:
      - ask
      summary: Ask By Voice
      description: "Voice → transcript → answer, streamed as SSE.\n\nEvent sequence:\n  1. `data: {\"\
        transcript\": \"...\"}\\n\\n`  (single event; iOS\n     pops the question bubble out of its \"\
        \U0001F3A4 transcribing…\"\n     placeholder using this string).\n  2. `data: {\"text\": \"...\"\
        }\\n\\n` × N  (answer chunks, 30 ms/word).\n  3. `data: {\"citation\": {...}}\\n\\n` × M  (citation\
        \ rows).\n  4. `data: [DONE]\\n\\n`.\n\nError sequence: `data: {\"error\": \"...\"}\\n\\n` then\
        \ `[DONE]`."
      operationId: ask_by_voice_v1_ai_ask_by_voice_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AskByVoiceRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/ai/narrate:
    post:
      tags:
      - ask
      summary: Narrate
      operationId: narrate_v1_ai_narrate_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NarrateRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/agent/confirm-action:
    post:
      tags:
      - agent
      summary: Confirm Action
      description: "Validate + execute a pending agent action.\n\nFlow:\n  1. Per-user rate-limit gate.\n\
        \  2. Verify token signature + look up PendingAction row.\n  3. Mark consumed (single-use enforcement).\n\
        \  4. Look up the right executor by `row.kind`.\n  5. Execute the write. Audit-log success or\
        \ error.\n\nReturns 200 with `ok=true` on success; 200 with `ok=false` +\n`error=<code>` when\
        \ the executor refuses (preserves a single\nresponse shape so iOS doesn't switch on HTTP status).\
        \ 4xx is\nreserved for token-validation failures + 429 for rate limit."
      operationId: confirm_action_v1_agent_confirm_action_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfirmActionRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfirmActionResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/agent/deny-action:
    post:
      tags:
      - agent
      summary: Deny Action
      description: 'User explicitly declined the agent''s proposed write. Marks the

        pending action consumed + audit-logs the denial.


        Same token-validation surface as confirm-action; refuses

        silently-existent attempts the same way. Shares the confirm

        rate-limit budget — denies are part of the same "agent action

        resolution" flow.'
      operationId: deny_action_v1_agent_deny_action_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DenyActionRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Deny Action V1 Agent Deny Action Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/ask-history:
    get:
      tags:
      - agent
      summary: List Ask History
      description: "List the caller's past Ask interactions, most-recent first.\n\nArgs:\n    limit: page\
        \ size, 1-200.\n    before: cursor — return rows with created_at < this. Lets the\n        client\
        \ paginate backward through history without dealing\n        with offset-based instability."
      operationId: list_ask_history_v1_me_ask_history_get
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: before
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Before
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AskHistoryResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - agent
      summary: Delete All Ask History
      description: 'Wipe ALL of the caller''s ask-history rows. The 90-day sweeper

        would catch them eventually; this endpoint is for users who want

        to clear the slate immediately.'
      operationId: delete_all_ask_history_v1_me_ask_history_delete
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Delete All Ask History V1 Me Ask History Delete
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/ask-history/{interaction_id}:
    delete:
      tags:
      - agent
      summary: Delete Ask History Item
      description: Delete a single ask-history row owned by the caller.
      operationId: delete_ask_history_item_v1_me_ask_history__interaction_id__delete
      parameters:
      - name: interaction_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Interaction Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Delete Ask History Item V1 Me Ask History  Interaction Id  Delete
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/agent-profile:
    get:
      tags:
      - agent
      summary: Get Agent Profile
      description: 'Return what the derivation worker has stored for the caller.


        Both rows are nullable for new users (no asks yet → no

        derivation has run). The endpoint returns empty dicts in that

        case so the iOS view can render "Nothing derived yet" cleanly.'
      operationId: get_agent_profile_v1_me_agent_profile_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentProfileResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - agent
      summary: Reset Agent Profile
      description: 'Wipe BOTH the agent_identity_profile + agent_user_profile rows

        for this user. Next derivation tick will rebuild from scratch.

        Doesn''t touch MemoryItem or ask_interactions — those have their

        own surfaces (`clear_memory` tool / Ask history view).'
      operationId: reset_agent_profile_v1_me_agent_profile_delete
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Reset Agent Profile V1 Me Agent Profile Delete
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/agent-profile/corrections:
    patch:
      tags:
      - agent
      summary: Patch Agent Profile Corrections
      description: 'Replace the user''s corrections with the supplied dict. iOS

        sends the full dict each time (no partial-merge semantics) so

        the wire shape is unambiguous + the endpoint is idempotent.'
      operationId: patch_agent_profile_corrections_v1_me_agent_profile_corrections_patch
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchCorrectionsRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Patch Agent Profile Corrections V1 Me Agent Profile Corrections Patch
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/ai/thread-assistant:
    post:
      tags:
      - thread_assistant
      summary: Thread Assistant
      description: 'Stream a private LLM answer about the current thread.


        Validates the caller is a member of `thread_id`, applies a per-user

        rate budget, then proxies to the OpenAI-compat LLM with a

        thread-scoped system prompt. Returns SSE.'
      operationId: thread_assistant_v1_ai_thread_assistant_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThreadAssistRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/ai/thread-assistant-by-voice:
    post:
      tags:
      - thread_assistant
      summary: Thread Assistant By Voice
      description: "Voice variant of ``/v1/ai/thread-assistant``.\n\nSteps:\n  1. Validate membership\
        \ + AI-enabled (same as text variant).\n  2. Decode base64 audio, run the production ``GemmaAudioTranscriber``\n\
        \     (the same one that handles voice notes — full Gemma-4 audio\n     multimodal path, NOT on-device\
        \ speech recognition).\n  3. Emit the transcript as the first SSE event so the iOS bubble\n  \
        \   can render the question text the user asked.\n  4. Stream the answer using the same ``_stream_assistant``\
        \ flow as\n     the text endpoint — same system prompt, same thread context.\n\nReturns SSE. Event\
        \ shapes:\n  - ``data: {\"transcript\":\"<text>\"}`` exactly once (or\n    ``data: {\"error\"\
        :\"...\"}`` then ``[DONE]`` if transcription\n    fails).\n  - ``data: {\"text\":\"<chunk>\"}``\
        \ for the streamed answer.\n  - ``data: [DONE]`` at end."
      operationId: thread_assistant_by_voice_v1_ai_thread_assistant_by_voice_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThreadAssistByVoiceRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant:
    get:
      tags:
      - personal_assistant
      summary: Get Assistant
      operationId: get_assistant_v1_me_assistant_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    patch:
      tags:
      - personal_assistant
      summary: Update Assistant
      operationId: update_assistant_v1_me_assistant_patch
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssistantSettingsPatch'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/instructions/reset:
    post:
      tags:
      - personal_assistant
      summary: Reset Assistant Instructions
      operationId: reset_assistant_instructions_v1_me_assistant_instructions_reset_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/permissions:
    put:
      tags:
      - personal_assistant
      summary: Update Assistant Permissions
      operationId: update_assistant_permissions_v1_me_assistant_permissions_put
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssistantPermissionsInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/activity:
    get:
      tags:
      - personal_assistant
      summary: List Assistant Activity
      operationId: list_assistant_activity_v1_me_assistant_activity_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AssistantActionView'
                title: Response List Assistant Activity V1 Me Assistant Activity Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/assistants/me:
    post:
      tags:
      - personal_assistant
      summary: Add My Assistant To Thread
      operationId: add_my_assistant_to_thread_v1_threads__thread_id__assistants_me_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssistantThreadInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantThreadMembershipView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - personal_assistant
      summary: Get My Assistant Thread Membership
      operationId: get_my_assistant_thread_membership_v1_threads__thread_id__assistants_me_get
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantThreadMembershipView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - personal_assistant
      summary: Remove My Assistant From Thread
      operationId: remove_my_assistant_from_thread_v1_threads__thread_id__assistants_me_delete
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantThreadMembershipView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/assistant-brief:
    get:
      tags:
      - personal_assistant
      summary: Assistant Thread Brief
      description: 'Proactive brief for a thread: a headline + the owner''s open commitments

        tied to it, prepared on open. Read-only; requires only thread membership

        (the assistant need not be added to the thread).'
      operationId: assistant_thread_brief_v1_threads__thread_id__assistant_brief_get
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantThreadBriefView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/assistant-invocations:
    post:
      tags:
      - personal_assistant
      summary: Invoke Assistant In Thread
      operationId: invoke_assistant_in_thread_v1_threads__thread_id__assistant_invocations_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssistantInvokeInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantInvocationResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/assistant-invocations/stream:
    post:
      tags:
      - personal_assistant
      summary: Invoke Assistant In Thread Stream
      description: 'SSE variant of :func:`invoke_assistant_in_thread`.


        Streams the agent''s step chrome, pending-action confirm cards, and a

        terminal ``result`` event. Universal gating failures are pre-checked

        before the stream opens so they still surface as real HTTP status

        codes (the iOS client maps those to upgrade / permission modals);

        once the stream is open, errors arrive as an in-band ``error`` event.'
      operationId: invoke_assistant_in_thread_stream_v1_threads__thread_id__assistant_invocations_stream_post
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssistantInvokeInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/approval-requests:
    post:
      tags:
      - personal_assistant
      summary: Create Assistant Approval Request
      operationId: create_assistant_approval_request_v1_me_assistant_approval_requests_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApprovalRequestInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalRequestView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/approval-requests/{approval_request_id}/approve:
    post:
      tags:
      - personal_assistant
      summary: Approve Assistant Action
      operationId: approve_assistant_action_v1_me_assistant_approval_requests__approval_request_id__approve_post
      parameters:
      - name: approval_request_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Approval Request Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantActionView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/actions/{action_id}/execute-public-thread-reply:
    post:
      tags:
      - personal_assistant
      summary: Execute Public Thread Reply
      operationId: execute_public_thread_reply_v1_me_assistant_actions__action_id__execute_public_thread_reply_post
      parameters:
      - name: action_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Action Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantActionView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/actions/{action_id}/undo:
    post:
      tags:
      - personal_assistant
      summary: Undo Assistant Action
      description: 'Retract an action the assistant took autonomously (AUTO authority),

        within its undo window. Returns the updated action (`output.undone=true`)

        or 400 `assistant_undo_window_expired` once the window has passed.'
      operationId: undo_assistant_action_v1_me_assistant_actions__action_id__undo_post
      parameters:
      - name: action_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Action Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantActionView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/actions/{action_id}/complete-client-action:
    post:
      tags:
      - personal_assistant
      summary: Complete Assistant Client Action
      operationId: complete_assistant_client_action_v1_me_assistant_actions__action_id__complete_client_action_post
      parameters:
      - name: action_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Action Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssistantClientActionCompleteInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantActionView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/me/assistant/approval-requests/{approval_request_id}/reject:
    post:
      tags:
      - personal_assistant
      summary: Reject Assistant Action
      operationId: reject_assistant_action_v1_me_assistant_approval_requests__approval_request_id__reject_post
      parameters:
      - name: approval_request_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Approval Request Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantActionView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/threads/{thread_id}/trust:
    get:
      tags:
      - trust
      summary: Thread Trust
      operationId: thread_trust_v1_threads__thread_id__trust_get
      parameters:
      - name: thread_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Thread Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrustResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/runtime:
    get:
      tags:
      - runtime
      summary: Get Runtime Config
      description: 'Single endpoint for hot-updatable client config.


        Auth required so we can do per-user overlays + audit who saw which

        config when chasing tester reports. The body is small (<5KB) and

        cacheable; iOS hits this on cold start and every 5 min thereafter.


        VD-OPS-001 round-7: feature flag resolution now flows through

        ``resolve_effective_flags`` instead of a static dict lookup.

        DB-backed ``feature_flags`` rows beat ``_FEATURES_DEFAULTS``

        (which is now treated as the legacy fallback layer); rows

        scoped to the caller''s workspace beat global rows; expired rows

        are ignored. ``env`` filters by the running environment so a

        ``dev``-only flag never reaches a prod client.


        The legacy ``_user_overrides`` overlay still applies on top of

        the resolved values — when v1.x audience tags ship, those will

        move into the same DB-backed flag table.'
      operationId: get_runtime_config_v1_runtime_get
      parameters:
      - name: lang
        in: query
        required: false
        schema:
          type: string
          minLength: 2
          maxLength: 8
          default: en
          title: Lang
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeConfigResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/feature-flags:
    get:
      tags:
      - feature-flags-admin
      summary: List Effective Flags
      description: 'Return the effective flag map for the caller''s workspace.


        No legacy ``static_defaults`` overlay here — the operator

        console wants to see exactly what comes from ``feature_flags``

        + the flags-module built-ins, NOT the runtime.py legacy

        fallback (which is a client-display concern, not an

        operational truth source). To get the iOS-equivalent view,

        hit ``GET /v1/runtime``.'
      operationId: list_effective_flags_v1_admin_feature_flags_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EffectiveFlagsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - feature-flags-admin
      summary: Flip Feature Flag
      description: 'Flip a feature flag and write an audit row.


        Both writes (the upsert into ``feature_flags`` and the insert

        into ``feature_flag_audit``) happen in the same db session so

        the audit record can never disagree with the live state. We

        don''t open an explicit transaction — the request handler

        runs inside one already.'
      operationId: flip_feature_flag_v1_admin_feature_flags_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FlagFlipRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FlagAuditRow'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/feature-flags/provenance:
    get:
      tags:
      - feature-flags-admin
      summary: List Effective Flags With Provenance
      description: 'Same scope as ``GET /v1/admin/feature-flags`` but every flag

        carries provenance — *which* row supplied the value, when, by

        whom, why, and when it auto-reverts (if at all).


        Use case: operator console wants to render "memory_tab is

        False because of global row set by alice@telbox.ai 3 days

        ago, expires never" rather than just "memory_tab: false."'
      operationId: list_effective_flags_with_provenance_v1_admin_feature_flags_provenance_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EffectiveFlagsWithProvenanceResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/feature-flags/{name}/audit:
    get:
      tags:
      - feature-flags-admin
      summary: Get Flag Audit
      description: 'Return the most-recent ``limit`` flips for ``name``, newest

        first. Hits the ``ix_feature_flag_audit_name_occurred`` index

        so the lookup stays cheap even after years of audit history.'
      operationId: get_flag_audit_v1_admin_feature_flags__name__audit_get
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
          title: Name
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FlagAuditRow'
                title: Response Get Flag Audit V1 Admin Feature Flags  Name  Audit Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/session:
    get:
      tags:
      - operator
      summary: Operator Session
      operationId: operator_session_v1_operator_session_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperatorSessionResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/tenant/health:
    get:
      tags:
      - operator
      summary: Tenant Health
      operationId: tenant_health_v1_operator_tenant_health_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantHealthResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/control-plane/status:
    get:
      tags:
      - operator
      summary: Control Plane Status
      operationId: control_plane_status_v1_operator_control_plane_status_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantHealthResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/inbox:
    get:
      tags:
      - operator
      summary: Operator Inbox
      operationId: operator_inbox_v1_operator_inbox_get
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperatorInboxResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/cases:
    get:
      tags:
      - operator
      summary: List Cases
      operationId: list_cases_v1_operator_cases_get
      parameters:
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - $ref: '#/components/schemas/CaseStatus'
          - type: 'null'
          title: Status
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CaseView'
                title: Response List Cases V1 Operator Cases Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - operator
      summary: Create Case
      operationId: create_case_v1_operator_cases_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CaseCreateRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CaseView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/cases/{case_id}:
    get:
      tags:
      - operator
      summary: Get Case
      operationId: get_case_v1_operator_cases__case_id__get
      parameters:
      - name: case_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Case Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CaseDetailResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/cases/{case_id}/actions:
    post:
      tags:
      - operator
      summary: Create Case Action
      operationId: create_case_action_v1_operator_cases__case_id__actions_post
      parameters:
      - name: case_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Case Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CaseActionRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CaseActionView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/messages/send:
    post:
      tags:
      - operator
      summary: Operator Send Message
      operationId: operator_send_message_v1_operator_messages_send_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OperatorMessageSendRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendMessageResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/jit/decide:
    post:
      tags:
      - operator
      summary: Jit Decide
      operationId: jit_decide_v1_operator_jit_decide_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JitDecideRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JitDecisionView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/jit/issue:
    post:
      tags:
      - operator
      summary: Jit Issue
      operationId: jit_issue_v1_operator_jit_issue_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JitIssueRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JitGrantView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/jit/{grant_id}/revoke:
    post:
      tags:
      - operator
      summary: Jit Revoke
      operationId: jit_revoke_v1_operator_jit__grant_id__revoke_post
      parameters:
      - name: grant_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Grant Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JitRevokeRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JitGrantView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/audit:
    get:
      tags:
      - operator
      summary: Audit List
      operationId: audit_list_v1_operator_audit_get
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 500
          minimum: 1
          default: 100
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuditListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/audit/drain:
    post:
      tags:
      - operator
      summary: Audit Drain
      operationId: audit_drain_v1_operator_audit_drain_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuditDrainRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuditDrainResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/exports:
    post:
      tags:
      - operator
      summary: Create Export
      operationId: create_export_v1_operator_exports_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExportCreateRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupervisoryExportView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/exports/{export_id}:
    get:
      tags:
      - operator
      summary: Get Export
      operationId: get_export_v1_operator_exports__export_id__get
      parameters:
      - name: export_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Export Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupervisoryExportView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/incidents:
    post:
      tags:
      - operator
      summary: Create Incident
      operationId: create_incident_v1_operator_incidents_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IncidentCreateRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IncidentView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/runtime-config:
    post:
      tags:
      - operator
      summary: Update Runtime Config
      operationId: update_runtime_config_v1_operator_runtime_config_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RuntimeFlagRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeFlagResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/operator/bank-context/{customer_ref}:
    get:
      tags:
      - operator
      summary: Bank Context
      operationId: bank_context_v1_operator_bank_context__customer_ref__get
      parameters:
      - name: customer_ref
        in: path
        required: true
        schema:
          type: string
          title: Customer Ref
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BankContextResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/backup:
    put:
      tags:
      - backup
      summary: Upsert Backup
      description: "Create or replace the caller's backup envelope.\n\nThe client is expected to have:\n\
        \  1. Asked the user for a passphrase (with strength guidance).\n  2. Generated a fresh random\
        \ salt.\n  3. Run the KDF to derive a symmetric key.\n  4. Encrypted the recovery payload (private\
        \ keys + tiny metadata)\n     with ChaCha20-Poly1305, prepending the random nonce.\n  5. POSTed\
        \ the ciphertext + salt + KDF identifier here."
      operationId: upsert_backup_v1_backup_put
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BackupPutInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BackupStatusView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - backup
      summary: Get Backup
      description: 'Return the caller''s backup envelope.


        Used during restore: the new device, post-OTP-sign-in, asks for the

        envelope, prompts the user for the passphrase, derives the key

        locally, and decrypts. If the user has no backup, returns 404 so

        the iOS client can branch to the "no backup found" path.'
      operationId: get_backup_v1_backup_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BackupView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - backup
      summary: Delete Backup
      description: 'Permanently delete the caller''s backup envelope.


        Idempotent — deleting a non-existent backup returns 204 just the

        same. We don''t 404 here because the user-visible action is "make

        sure no backup exists," and a 404 would force the client to handle

        a non-error as if it were one.'
      operationId: delete_backup_v1_backup_delete
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/backup/status:
    get:
      tags:
      - backup
      summary: Get Backup Status
      description: 'Cheap "is a backup configured?" probe for the Settings UI.


        Doesn''t return the ciphertext — render the toggle without a full

        envelope download. The Settings page calls this on every appear.'
      operationId: get_backup_status_v1_backup_status_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BackupStatusView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls:
    post:
      tags:
      - calls
      summary: Start Call
      description: 'Start a call in a thread. Caller becomes the initiator and is

        auto-joined. Other thread members (or the explicit invitee

        subset) are invited and start in `ringing` status.'
      operationId: start_call_v1_calls_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartCallInput'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/incoming:
    get:
      tags:
      - calls
      summary: List Incoming Calls
      description: 'Return ringing calls where the caller is still invited.


        WebSocket ``call.invited`` is intentionally low-latency but transient:

        iOS can briefly suspend/reconnect a socket during foreground transitions.

        Clients use this endpoint on launch/reconnect/foreground to recover a

        missed invite before it turns into a false missed call.'
      operationId: list_incoming_calls_v1_calls_incoming_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CallView'
                title: Response List Incoming Calls V1 Calls Incoming Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/pre-call-context:
    get:
      tags:
      - calls
      summary: Pre Call Context
      description: 'Aggregated brief for the 3-8s ring window.


        Wrapped in a try/except per data source so a slow Postgres on

        memories doesn''t block the affordance entirely — the card

        degrades to whatever data was fetched in time.'
      operationId: pre_call_context_v1_calls__call_id__pre_call_context_get
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PreCallContextView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/workspaces/{workspace_id}/cross-call-entities:
    get:
      tags:
      - calls
      summary: Cross Call Entities
      description: 'Recurring entities that surfaced across N+ calls in this

        workspace within the last ``since_days``.


        Authorization: caller must be a workspace member. Greedy cosine

        clustering — fine for the volumes seen in production today

        (typically < 200 call-grounded memories per workspace per month).


        Result is sorted by mention_count descending so the most-talked-

        about entities surface first.'
      operationId: cross_call_entities_v1_workspaces__workspace_id__cross_call_entities_get
      parameters:
      - name: workspace_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Workspace Id
      - name: since_days
        in: query
        required: false
        schema:
          type: integer
          maximum: 365
          minimum: 1
          default: 30
          title: Since Days
      - name: min_mentions
        in: query
        required: false
        schema:
          type: integer
          maximum: 10
          minimum: 2
          default: 2
          title: Min Mentions
      - name: similarity_threshold
        in: query
        required: false
        schema:
          type: number
          maximum: 0.99
          minimum: 0.5
          default: 0.78
          title: Similarity Threshold
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CrossCallEntityView'
                title: Response Cross Call Entities V1 Workspaces  Workspace Id  Cross Call Entities Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}:
    get:
      tags:
      - calls
      summary: Get Call
      description: 'Fetch the current call state. Used by clients to refresh the

        participant list and reconcile after disconnects.'
      operationId: get_call_v1_calls__call_id__get
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/accept:
    post:
      tags:
      - calls
      summary: Accept Call
      description: 'Mark the caller as joined. First device to accept wins; later

        accepts on the user''s other devices are no-ops (status already

        JOINED). The call transitions RINGING → ACTIVE on the first

        accept (initiator alone doesn''t count as ACTIVE).'
      operationId: accept_call_v1_calls__call_id__accept_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AcceptCallInput'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/decline:
    post:
      tags:
      - calls
      summary: Decline Call
      description: 'Mark the caller as declined (terminal). If the caller is the

        only outstanding invitee and no one has joined, the whole call

        transitions to ENDED.'
      operationId: decline_call_v1_calls__call_id__decline_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/leave:
    post:
      tags:
      - calls
      summary: Leave Call
      description: 'Caller leaves the call. When the last joined participant leaves,

        the call transitions to ENDED and AI processing of segments is

        triggered (next backend pass).'
      operationId: leave_call_v1_calls__call_id__leave_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/segments:
    post:
      tags:
      - calls
      summary: Upload Segment
      description: 'Upload one encrypted mic chunk. Caller must be (or have been) a

        joined participant. Server stores ciphertext only; the AI processor

        (or the user''s own device on restore) is the only thing that ever

        decrypts. Wrapped session keys for recipient devices live in a

        sibling table in v1.x — for v1 we wrap to a single recipient

        (the AI processor) and skip the recipients table.'
      operationId: upload_segment_v1_calls__call_id__segments_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SegmentUploadInput'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentUploadResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/segments/begin:
    post:
      tags:
      - calls
      summary: Begin Segment Upload
      description: 'Reserve a CallSegment row + return a signed PUT URL for the

        AEAD ciphertext. The client uploads to GCS directly (typically via

        a background-priority URLSession on iOS), then calls

        ``POST /v1/calls/{id}/segments/{seg_id}/finalize`` to publish

        ``CallSegmentUploaded`` to the worker.


        Validation done up-front (caller is participant, envelope is

        wrapped to the workspace AI processor, content_length is sane)

        so a misbehaving client can''t waste a signed-URL round trip on a

        segment we''d refuse on finalize anyway.'
      operationId: begin_segment_upload_v1_calls__call_id__segments_begin_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SegmentBeginInput'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentBeginResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/segments/{segment_id}/finalize:
    post:
      tags:
      - calls
      summary: Finalize Segment Upload
      description: 'Confirm a direct-to-GCS upload + publish ``CallSegmentUploaded``.


        The client calls this AFTER the signed-URL PUT completes

        successfully. We verify the object exists in GCS (cheap HEAD)

        before publishing so the worker doesn''t pick up a phantom segment

        that the client never actually uploaded — common when the

        background URLSession upload silently failed (network change,

        app killed mid-PUT). If GCS doesn''t have the object, the row is

        marked failed and the worker is NOT notified.'
      operationId: finalize_segment_upload_v1_calls__call_id__segments__segment_id__finalize_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: segment_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Segment Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SegmentUploadResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/afs-frames:
    post:
      tags:
      - calls
      summary: Upload Afs Frames
      description: 'Upload encrypted WaveLink v2 AFS layers for canonical audio.


        AFS is deliberately not live media. The client sends post-handshake

        or post-call encrypted layers here when uplink slack exists. The

        API indexes them by call/speaker/RIS sequence so the canonical

        reconstruction worker can merge late fidelity layers without

        scanning object storage.'
      operationId: upload_afs_frames_v1_calls__call_id__afs_frames_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AFSFramesUploadInput'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AFSFramesUploadResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/listen-back/token:
    post:
      tags:
      - calls
      summary: Issue Listenback Token
      description: 'Mint a short-lived listen-back capability token for the caller.


        Authorization: caller must be JWT-authenticated AND a participant

        of the call. The minted token is scoped to (call_id, caller); a

        separate request must be made per call.'
      operationId: issue_listenback_token_v1_calls__call_id__listen_back_token_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CanonicalListenbackTokenView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/canonical/{speaker_id}.wav:
    get:
      tags:
      - calls
      summary: Get Canonical Per Speaker Wav
      description: 'Stream the per-speaker canonical WAV. Caller must present a

        valid capability token (minted via the listen-back endpoint above).

        The capability is verified for (call_id, caller) scope match.


        Returns 404 if the speaker has no per-speaker stream after

        reconstruction (every byte failed to decrypt).'
      operationId: get_canonical_per_speaker_wav_v1_calls__call_id__canonical__speaker_id__wav_get
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: speaker_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Speaker Id
      - name: token
        in: query
        required: true
        schema:
          type: string
          description: canonical_read_for_listenback capability token
          title: Token
        description: canonical_read_for_listenback capability token
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Per-speaker canonical WAV.
          content:
            application/json:
              schema: {}
            audio/wav: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/canonical/mixed.wav:
    get:
      tags:
      - calls
      summary: Get Canonical Mixed Wav
      description: 'Stream the mixed canonical WAV — the sum of per-speaker streams

        with sample-aligned alignment + Int16 clip. Capability must grant

        the mixed view (ASR-only capabilities don''t qualify).'
      operationId: get_canonical_mixed_wav_v1_calls__call_id__canonical_mixed_wav_get
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: token
        in: query
        required: true
        schema:
          type: string
          description: canonical_read_for_listenback capability token
          title: Token
        description: canonical_read_for_listenback capability token
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Mixed canonical WAV (sample-aligned sum of per-speaker streams).
          content:
            application/json:
              schema: {}
            audio/wav: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/signal:
    post:
      tags:
      - calls
      summary: Persist and notify a WaveLink handshake signal to a peer device (B-5 durable signaling).
      description: "Relay an opaque WaveLink signaling blob from the caller's\ncurrent device to another\
        \ device in the same call. Replaces the\nWebSocket ``call.signal`` message kind (which silently\
        \ dropped\nsignals whenever the WS reconnected between enqueue and recipient\ndelivery — failure\
        \ mode #16 in the cross-network call-setup audit).\n\nSame authentication as the WS handler ``_handle_call_signal``\
        \ in\n``telbox.api.ws``:\n\n  1. The caller's device must be the participant's bound\n     ``device_id``\
        \ (or any pre-bound device for an ``INVITED``\n     participant — relay_auth.call_participant_device_is_authorized\n\
        \     encodes this contract).\n  2. The recipient's device must be the participant's bound\n \
        \    ``device_id`` (or any device for an ``INVITED`` participant).\n  3. Both must be in (``INVITED``,\
        \ ``JOINED``).\n\nThe signal is persisted first into a short-lived recipient inbox,\nthen opportunistically\
        \ pushed via realtime. Mobile WebSockets can\nbe suspended or ``connecting`` while HTTPS is healthy;\
        \ the durable\ninbox is the source of truth and WS is only the low-latency wakeup."
      operationId: post_call_signal_v1_calls__call_id__signal_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CallSignalBody'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallSignalAck'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/signals:
    get:
      tags:
      - calls
      summary: Pull missed WaveLink call signals for the caller's device.
      description: 'Return unexpired, unacked signaling blobs addressed to this device.


        This is the receive-side reliability path for mobile clients whose

        WebSocket was suspended/reconnecting during endpoint exchange.'
      operationId: list_call_signals_v1_calls__call_id__signals_get
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: after_seq
        in: query
        required: false
        schema:
          type: integer
          minimum: 0
          default: 0
          title: After Seq
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 50
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallSignalList'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/metrics:
    post:
      tags:
      - calls
      summary: Upload Call Metrics
      description: 'Receive the iOS-side per-call quality summary at call end.


        Idempotent on (call_id, device_id): a repeated POST from the

        same device replaces the previous row for that device on that

        call. This matches the iOS retry contract: the summary is

        posted best-effort after /leave; if the network blip eats the

        first one, the device retries on next foreground.'
      operationId: upload_call_metrics_v1_calls__call_id__metrics_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CallQualityReport'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/trace-events:
    post:
      tags:
      - calls
      summary: Upload Call Trace Events
      description: 'Receive durable, idempotent WaveLink setup/path trace events.


        These events are deliberately lower level than the call-quality

        aggregate. They preserve the exact sequence of client-observed

        audio activation, STUN, Noise, path switch, and first-audio

        milestones so support can replay a failed setup after the fact.'
      operationId: upload_call_trace_events_v1_calls__call_id__trace_events_post
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CallTraceUpload'
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - calls
      summary: Get Call Trace Events
      description: Return a time-ordered replay of WaveLink setup/path trace events.
      operationId: get_call_trace_events_v1_calls__call_id__trace_events_get
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 2000
          minimum: 1
          default: 500
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallTraceView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/calls/{call_id}/quality:
    get:
      tags:
      - calls
      summary: Get Call Quality
      description: 'Aggregate per-call quality across every participant device.


        Used by the operator portal "why was this call bad?" view and

        by post-incident debugging. Caller must be a participant; no

        cross-workspace leakage.'
      operationId: get_call_quality_v1_calls__call_id__quality_get
      parameters:
      - name: call_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Call Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallQualityView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/insights:
    post:
      tags:
      - insights
      summary: Generate Insights
      description: 'Run the on-demand AI insights stages (Extract + Summarize + Replies)

        against a message. Streams per-stage progress via the existing

        `ai.stage_done` WS events so the open AIInsightSheet on iOS lights

        up sections one at a time without waiting for the whole batch.'
      operationId: generate_insights_v1_messages__message_id__insights_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InsightsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/translate-stream:
    post:
      tags:
      - translate
      summary: Translate Stream
      operationId: translate_stream_v1_messages__message_id__translate_stream_post
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        content:
          application/json:
            schema:
              anyOf:
              - $ref: '#/components/schemas/TranslateStreamRequest'
              - type: 'null'
              title: Body
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/messages/{message_id}/diagnostic:
    get:
      tags:
      - diagnostic
      summary: Message Diagnostic
      operationId: message_diagnostic_v1_messages__message_id__diagnostic_get
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Message Diagnostic V1 Messages  Message Id  Diagnostic Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/metrics:
    get:
      tags:
      - metrics
      summary: Metrics
      description: 'Prometheus text-exposition endpoint.


        Content-Type per RFC: ``text/plain; version=0.0.4; charset=utf-8``.'
      operationId: metrics_v1_metrics_get
      parameters:
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            text/plain:
              schema:
                type: string
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /v1/admin/network-metrics:
    get:
      tags:
      - admin-network-metrics
      summary: Aggregate counters for the consumer homeserver + directory
      description: 'Read-only aggregate counters. Cheap; runs five COUNT queries

        against indexed timestamp columns. Reasonable to call every

        refresh in the founder dashboard.


        ``push_success_rate_24h`` is derived from ``outbox_events``:

        ``completed_at IS NOT NULL`` over total enqueued in the window.

        Returns ``0.0`` when no outbox traffic in the window — better

        than dividing by zero.'
      operationId: get_network_metrics_v1_admin_network_metrics_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NetworkMetricsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/ops-dashboard:
    get:
      tags:
      - admin-ops-dashboard
      summary: Master operations dashboard payload (business + ops + tech)
      description: 'Single aggregated read for the master dashboard.


        Cost is bounded: ~12 indexed COUNT queries on Postgres + one cached

        Cloud Monitoring infra snapshot (30 s TTL) + one Redis-backed call to

        ``outbox_depth``. Designed to be polled every 10 seconds without

        spiking load.


        ``since`` controls the lookback window: ``5m``..``30d`` (default

        24h). The current-state windows (active calls, 5-minute device

        count, 1-hour message rate) ignore ``since`` because they describe

        *now*, not history.


        Auth is enforced by ``AdminCallerDep`` (founder session in prod).'
      operationId: get_ops_dashboard_v1_admin_ops_dashboard_get
      parameters:
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Since
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpsDashboardResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/ops-dashboard/stream:
    get:
      tags:
      - admin-ops-dashboard
      summary: Master Ops Dashboard — Server-Sent Events live stream
      description: 'Server-Sent Events stream of dashboard snapshots.


        Emits one ``data: <json>\n\n`` frame every ``SNAPSHOT_INTERVAL``

        seconds. The frontend uses an EventSource to consume this so the

        UI updates without explicit polling and the connection

        automatically reconnects on transient failure.


        Note: SSE is one-way (server → client); request bodies / query

        params don''t change after the initial GET. Filters belong on the

        non-streaming endpoint.'
      operationId: stream_ops_dashboard_v1_admin_ops_dashboard_stream_get
      parameters:
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Since
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/messages/{message_id}/transitions:
    get:
      tags:
      - admin-ops-dashboard
      summary: Full status-transition timeline for one message
      description: 'Forensic drill-in for the "why did this message fail?" question.


        Reads the ``message_state_transitions`` audit table for the

        specified message + the live snapshot of the lease columns on

        ``messages``. Designed for the dashboard''s "show the timeline"

        affordance and on-call triage.'
      operationId: get_message_transitions_v1_admin_messages__message_id__transitions_get
      parameters:
      - name: message_id
        in: path
        required: true
        schema:
          type: string
          title: Message Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageTransitionHistory'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/subscriptions:
    get:
      tags:
      - admin-insights
      summary: Get Subscriptions
      operationId: get_subscriptions_v1_admin_subscriptions_get
      parameters:
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Since
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionsSnapshot'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/ai-usage:
    get:
      tags:
      - admin-insights
      summary: Get Ai Usage
      operationId: get_ai_usage_v1_admin_ai_usage_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AIUsageSnapshot'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/security:
    get:
      tags:
      - admin-insights
      summary: Get Security
      operationId: get_security_v1_admin_security_get
      parameters:
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Since
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecuritySnapshot'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/devices:
    get:
      tags:
      - admin-insights
      summary: Get Devices
      operationId: get_devices_v1_admin_devices_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DevicesSnapshot'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/compliance:
    get:
      tags:
      - admin-insights
      summary: Get Compliance
      operationId: get_compliance_v1_admin_compliance_get
      parameters:
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Since
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComplianceSnapshot'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/platform-audit:
    get:
      tags:
      - admin-audit
      summary: List platform-level admin actions (Wave 6d)
      description: 'Returns the most recent platform-audit entries, newest first.

        Each entry is a hash-chained record signed at insert time by the

        audit service; tampering is detectable via

        ``PlatformAuditService.verify_chain``.'
      operationId: list_platform_audit_v1_admin_platform_audit_get
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 1000
          minimum: 1
          default: 200
          title: Limit
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformAuditResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/pipelines/workflows:
    get:
      tags:
      - admin-pipelines
      summary: List workflows defined in the repository
      operationId: list_workflows_v1_admin_pipelines_workflows_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/pipelines/runs:
    get:
      tags:
      - admin-pipelines
      summary: List recent workflow runs (across one workflow or all)
      description: 'Returns the most recent `limit` runs. Optionally narrow to a

        specific workflow_id (matches GitHub''s filter) or branch.'
      operationId: list_runs_v1_admin_pipelines_runs_get
      parameters:
      - name: workflow_id
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
            minimum: 1
          - type: 'null'
          title: Workflow Id
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 20
          title: Limit
      - name: branch
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 200
          - type: 'null'
          title: Branch
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/ai-policy:
    get:
      tags:
      - admin-ai-policy
      summary: Read the active AI policy
      description: 'Returns the active policy + when/by-whom it was last changed.

        On a fresh deployment with no row yet, returns the deny-all

        default with `updated_by_actor=None` so the founder portal can

        render an "unconfigured" hint.'
      operationId: read_policy_v1_admin_ai_policy_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicyOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    put:
      tags:
      - admin-ai-policy
      summary: Replace the active AI policy
      description: 'Replace the policy. Audited; cache invalidated. The next

        inference call (transcriber / understander dispatch) re-reads

        the cache and consults the new policy.'
      operationId: set_policy_v1_admin_ai_policy_put
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PolicySetRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicySetResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/users/{user_id}/ai-quota-override:
    post:
      tags:
      - admin-ai-quota-override
      summary: Set Override
      description: Replace the user's AI quota override. Audit-logged.
      operationId: set_override_v1_admin_users__user_id__ai_quota_override_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OverrideBody'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OverrideResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - admin-ai-quota-override
      summary: Get Override
      description: 'Read the user''s current override + effective-cap preview.


        The ``caller`` argument is unused at the handler level — auth is

        enforced by :class:`AdminCallerDep`; declaring the parameter keeps

        the dependency in the FastAPI graph.'
      operationId: get_override_v1_admin_users__user_id__ai_quota_override_get
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OverrideResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - admin-ai-quota-override
      summary: Delete Override
      description: Clear the user's AI quota override. Audit-logged.
      operationId: delete_override_v1_admin_users__user_id__ai_quota_override_delete
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      - name: clear_is_internal
        in: query
        required: false
        schema:
          type: boolean
          description: Also clear ``users.is_internal`` (set to FALSE). Default is to leave is_internal
            alone — a tester who's already flagged as internal should stay internal even if an unrelated
            JSONB override is cleared.
          default: false
          title: Clear Is Internal
        description: Also clear ``users.is_internal`` (set to FALSE). Default is to leave is_internal
          alone — a tester who's already flagged as internal should stay internal even if an unrelated
          JSONB override is cleared.
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OverrideResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/directory/verifying-key:
    get:
      tags:
      - directory
      summary: Public verifying key + canonical-format version for the directory
      description: 'Public, no-auth — clients that fetch ``/v1/directory`` use this

        to verify each entry''s ``directory_signature`` against the active

        Telbox directory key. Pin the verifying key locally; rotate

        requires a coordinated client + server update.'
      operationId: get_directory_verifying_key_v1_directory_verifying_key_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DirectoryVerifyingKeyResponse'
      security: []
  /v1/directory:
    get:
      tags:
      - directory
      summary: List registered tenants in the trust+discovery plane
      description: 'Public, no-auth endpoint. Optional filters by region or

        status; the default returns all `active` entries across all

        regions.'
      operationId: list_directory_v1_directory_get
      parameters:
      - name: region
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 32
          - type: 'null'
          title: Region
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 16
          - type: 'null'
          title: Status
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DirectoryListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags:
      - directory
      summary: Register a new tenant in the directory (admin-gated)
      description: 'Admin-gated. Registers a new tenant. The

        `directory_signature` column is populated server-side; v0.1

        writes a placeholder until the directory-signing-key wiring

        lands. Once that ships the column will hold a real Ed25519

        signature over the canonical entry bytes by Telbox''s

        directory key.'
      operationId: register_directory_entry_v1_directory_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DirectoryRegisterRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DirectoryRegisterResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/directory/{fingerprint_hex}:
    get:
      tags:
      - directory
      summary: Look up one tenant by identity-key fingerprint
      description: 'Public, no-auth single-entry lookup. The fingerprint is the

        canonical lookup key — clients hash the tenant''s identity public

        key with BLAKE2s-256 and pass the lower-hex digest here.'
      operationId: get_directory_entry_v1_directory__fingerprint_hex__get
      parameters:
      - name: fingerprint_hex
        in: path
        required: true
        schema:
          type: string
          title: Fingerprint Hex
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DirectoryEntryOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    patch:
      tags:
      - directory
      summary: Update a tenant's lifecycle status (suspend/revoke/reactivate)
      description: 'Admin-gated. Flip a tenant between active/suspended/revoked.

        Loud audit on every transition so the founder portal''s audit

        view shows a complete lifecycle history per tenant.'
      operationId: update_directory_entry_status_v1_directory__fingerprint_hex__patch
      parameters:
      - name: fingerprint_hex
        in: path
        required: true
        schema:
          type: string
          title: Fingerprint Hex
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DirectoryStatusUpdateRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DirectoryEntryOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/founder-auth/request:
    post:
      tags:
      - founder-auth
      summary: Request a magic-link to authenticate to the founder portal
      description: 'Step 1 of the magic-link flow. Always returns a generic

        success response so an attacker can''t enumerate which emails

        are allow-listed. The platform audit captures every request

        (including denied attempts) so a brute-force scan against the

        allowlist is detectable from the chain.'
      operationId: request_magic_link_v1_founder_auth_request_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestMagicLinkRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestMagicLinkResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /v1/founder-auth/exchange:
    post:
      tags:
      - founder-auth
      summary: Exchange a magic-link token for a founder-portal session token
      description: 'Step 2 of the magic-link flow. Validates the magic JWT,

        mints an 8-hour session JWT. Audits both success + failure so

        the chain captures who actually exchanged.'
      operationId: exchange_magic_link_v1_founder_auth_exchange_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExchangeRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExchangeResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /v1/admin/api-docs:
    get:
      tags:
      - docs-portal
      summary: Interactive API reference (admin-only)
      description: 'Serve the Scalar API reference for authenticated admins.


        ``?spec=public`` renders the curated Voice Cloud subset; the default is the

        full internal surface.'
      operationId: api_docs_v1_admin_api_docs_get
      parameters:
      - name: spec
        in: query
        required: false
        schema:
          enum:
          - full
          - public
          type: string
          default: full
          title: Spec
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/admin/api-docs/openapi.json:
    get:
      tags:
      - docs-portal
      summary: Enriched OpenAPI document (admin-only)
      description: Return the raw enriched OpenAPI JSON (full or public subset).
      operationId: api_docs_openapi_v1_admin_api_docs_openapi_json_get
      parameters:
      - name: spec
        in: query
        required: false
        schema:
          enum:
          - full
          - public
          type: string
          default: full
          title: Spec
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/subpoenas:
    post:
      tags:
      - subpoenas
      summary: Submit a legal-process request to a tenant
      description: 'Control-plane composer creates one pending request. The

        ``requester_actor`` is captured from the caller; the row''s

        creation is loud-audited so the platform audit chain shows

        exactly who asked, when, of which tenant, with what scope.'
      operationId: create_subpoena_v1_subpoenas_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubpoenaCreateRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubpoenaCreateResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      tags:
      - subpoenas
      summary: List subpoena requests (filterable by tenant or requester)
      description: "Three patterns:\n- ``?target_tenant_fingerprint_hex=…`` — what's pending against\n\
        \  this tenant. The tenant's ComplianceOfficer queries this on\n  their inbox view.\n- ``?requester=…``\
        \ — what the caller has submitted. The\n  control-plane's submissions list.\n- No filter — admin-gated;\
        \ full cross-tenant view for\n  control-plane oversight."
      operationId: list_subpoenas_v1_subpoenas_get
      parameters:
      - name: target_tenant_fingerprint_hex
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            minLength: 64
            maxLength: 64
          - type: 'null'
          title: Target Tenant Fingerprint Hex
      - name: requester
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 200
          - type: 'null'
          title: Requester
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 16
          - type: 'null'
          title: Status
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubpoenaListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/subpoenas/{subpoena_id}/decide:
    post:
      tags:
      - subpoenas
      summary: Approve or deny a pending subpoena (tenant operator)
      description: 'The target tenant''s ComplianceOfficer flips a pending row

        to ``approved`` or ``denied``. Loud audit on every decision —

        the platform chain captures who decided what, when. The tenant''s

        own operator-portal audit chain captures the same event from

        their side once they wire this through ``record_subpoena_decided``

        (Wave 6f-2).'
      operationId: decide_subpoena_v1_subpoenas__subpoena_id__decide_post
      parameters:
      - name: subpoena_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Subpoena Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubpoenaDecideRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubpoenaOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/subscriptions/verify-receipt:
    post:
      tags:
      - subscriptions
      summary: Verify Receipt
      description: "Verify a StoreKit2 JWS receipt + flip the caller's tier.\n\nReturns 200 with the new\
        \ subscription status on success.\n\nError mapping:\n  - 400 ``apple_receipt_invalid`` when JWS\
        \ verification or product\n    mapping fails.\n  - 501 ``storekit_not_configured`` when the operator\
        \ has not set up\n    the Apple StoreKit settings."
      operationId: verify_receipt_v1_subscriptions_verify_receipt_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyReceiptRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerifyReceiptResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/subscriptions/apple/webhook:
    post:
      tags:
      - subscriptions
      summary: Apple Webhook
      description: "App Store Server Notifications V2 webhook.\n\nApple delivers POST with body ``{\"\
        signedPayload\": \"<JWS>\"}``. The JWS\nsignature is the only auth surface — there is no bearer\
        \ token. We\nverify the JWS chain + signature inside\n:mod:`telbox.modules.subscriptions.apple`\
        \ before any DB mutation.\n\nReturns 200 even on unhandled notification types so Apple stops\n\
        retrying. We log the type for analytics.\n\nIdempotency (premium-tier, 2026-05-18): Apple may\
        \ redeliver a\nnotification if the previous 200 OK wasn't observed in their\ntimeout window. Each\
        \ notification carries a stable ``notificationUUID``.\nWe INSERT into ``processed_apple_notifications``\
        \ on success; on a\nduplicate UUID the INSERT raises IntegrityError and we return 200\nwith ``handled=false``\
        \ so Apple stops retrying without re-running\n``apply_apple_notification`` (which would re-flip\
        \ tier / re-credit /\nre-emit lapsed pushes).\n\nOperator action: register this URL in App Store\
        \ Connect:\n  App → App Information → App Store Server Notifications V2\n  Production URL: https://api.telbox.ai/v1/subscriptions/apple/webhook\n\
        \  Sandbox URL:    same path on the staging API host"
      operationId: apple_webhook_v1_subscriptions_apple_webhook_post
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppleWebhookResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/subscriptions/status:
    get:
      tags:
      - subscriptions
      summary: Subscription Status
      description: 'Return the caller''s current subscription state. Used by the iOS

        subscription-management screen + the entitlement-resolver cache.'
      operationId: subscription_status_v1_subscriptions_status_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionStatusResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/subscriptions/lapsed-disclosure:
    get:
      tags:
      - subscriptions
      summary: Lapsed Disclosure
      description: 'Return the legal-reviewed copy block for the "your subscription

        lapsed" modal.


        The iOS app fetches this on receipt of the ``subscription.lapsed``

        push so the copy can be tuned server-side without a client release.'
      operationId: lapsed_disclosure_v1_subscriptions_lapsed_disclosure_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Lapsed Disclosure V1 Subscriptions Lapsed Disclosure Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /i/{ref}:
    get:
      summary: Invite Landing
      description: Render the share preview + click-through page for a given ref.
      operationId: invite_landing_i__ref__get
      parameters:
      - name: ref
        in: path
        required: true
        schema:
          type: string
          title: Ref
      responses:
        '200':
          description: Successful Response
          content:
            text/html:
              schema:
                type: string
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /a/{ref_token}/drop:
    post:
      summary: Submit Anon Drop
      description: 'Accept one anonymous voice drop addressed to the inviter who

        owns ``ref_token``. No authentication; rate-limited per ref.


        Optional ``phone`` (E.164) is hashed sha256 server-side and stored

        so that when this person later installs and verifies via OTP, the

        OTP-verify path can retroactively claim their drops into a real

        user account. The raw phone is NEVER persisted — only the hash.'
      operationId: submit_anon_drop_a__ref_token__drop_post
      parameters:
      - name: ref_token
        in: path
        required: true
        schema:
          type: string
          minLength: 4
          maxLength: 32
          title: Ref Token
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_submit_anon_drop_a__ref_token__drop_post'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/me/anon-drops:
    get:
      summary: List My Anon Drops
      description: 'List the inviter''s anonymous drops, newest first.


        Includes both unclaimed and recently-claimed (so the iOS UI can

        play the "X joined Telbox and their drops migrated" animation).'
      operationId: list_my_anon_drops_v1_me_anon_drops_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AnonDropListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/me/anon-drops/{drop_id}/audio:
    get:
      summary: Fetch Anon Drop Audio
      description: 'Stream a single anon-drop''s audio. Authorized for the drop''s

        inviter only. Used by iOS to play the recording in the bubble.'
      operationId: fetch_anon_drop_audio_v1_me_anon_drops__drop_id__audio_get
      parameters:
      - name: drop_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Drop Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/me/anon-drops/claimed:
    get:
      summary: List My Claimed Drops
      description: 'List drops the CALLER sent anonymously before they signed up,

        that were retroactively linked via the OTP-verify claim path.


        Surfaced in iOS as a "Drops you sent before signing up" section

        so the user knows their pre-account messages didn''t get lost.'
      operationId: list_my_claimed_drops_v1_me_anon_drops_claimed_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimedDropListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/me/anon-drops/claimed/{drop_id}/audio:
    get:
      summary: Fetch Claimed Drop Audio
      description: 'Stream a claimed drop''s audio. Authorized for the claimer

        (the user who eventually signed up and got linked) — separate

        auth from `fetch_anon_drop_audio` which authorizes the inviter.'
      operationId: fetch_claimed_drop_audio_v1_me_anon_drops_claimed__drop_id__audio_get
      parameters:
      - name: drop_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Drop Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/share:
    post:
      summary: Create Share Artifact
      description: Mint a public share URL for one artifact.
      operationId: create_share_artifact_v1_share_post
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ShareCreateRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShareCreateResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/share/mine:
    get:
      summary: List My Shares
      operationId: list_my_shares_v1_share_mine_get
      parameters:
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShareListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/share/{art_id}:
    delete:
      summary: Revoke Share
      operationId: revoke_share_v1_share__art_id__delete
      parameters:
      - name: art_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Art Id
      - name: access_token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Access Token
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: x-workspace-id
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Workspace-Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /s/{slug}:
    get:
      summary: Render Public Share
      operationId: render_public_share_s__slug__get
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          minLength: 4
          maxLength: 16
          title: Slug
      responses:
        '200':
          description: Successful Response
          content:
            text/html:
              schema:
                type: string
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
      tags:
      - sharing
  /v1/ws:
    get:
      tags:
      - realtime
      summary: WebSocket — realtime event stream
      description: '**This is a WebSocket endpoint, not a regular HTTP GET.**


        Connect with `wss://api.telbox.ai/v1/ws?token=<access_token>`. The server accepts the socket,
        then authenticates the token (closing with code `4401` on failure). Send the text frame `ping`
        to receive `pong`. Server→client messages use the event envelope `{type, thread_id, message_id?,
        workspace_id?, payload}`. See the **Realtime** guide for the full event catalog, reconnect/replay,
        and SSE streaming.'
      responses:
        '101':
          description: Switching Protocols — WebSocket upgrade.
        '4401':
          description: Authentication failed (close code).
        '401':
          $ref: '#/components/responses/Unauthorized'
      security: []
      x-telbox-protocol: websocket
components:
  schemas:
    AFSFrameUploadInput:
      properties:
        ris_seq:
          type: integer
          maximum: 281474976710655.0
          minimum: 0.0
          title: Ris Seq
        kind:
          type: string
          enum:
          - full_replacement
          - residual
          - post_call_only
          title: Kind
        priority:
          type: string
          enum:
          - live
          - eventually
          - idle_only
          title: Priority
          default: eventually
        ciphertext_b64:
          type: string
          title: Ciphertext B64
        nonce_b64:
          type: string
          title: Nonce B64
        aad_b64:
          type: string
          title: Aad B64
        signature_b64:
          type: string
          title: Signature B64
      type: object
      required:
      - ris_seq
      - kind
      - ciphertext_b64
      - nonce_b64
      - aad_b64
      - signature_b64
      title: AFSFrameUploadInput
    AFSFramesUploadInput:
      properties:
        wrapped_key_b64:
          type: string
          title: Wrapped Key B64
        sender_eph_public_b64:
          type: string
          title: Sender Eph Public B64
        envelope_version:
          type: integer
          title: Envelope Version
          default: 1
        frames:
          items:
            $ref: '#/components/schemas/AFSFrameUploadInput'
          type: array
          maxItems: 64
          minItems: 1
          title: Frames
      type: object
      required:
      - wrapped_key_b64
      - sender_eph_public_b64
      - frames
      title: AFSFramesUploadInput
      description: 'Encrypted AFS batch wrapped to the workspace AI processor.


        The server stores each ciphertext as opaque bytes. Decryption is

        reserved for the canonical reconstruction worker that runs with the

        AI processor private key.'
    AFSFramesUploadResult:
      properties:
        stored:
          type: integer
          title: Stored
        duplicates:
          type: integer
          title: Duplicates
        frame_ids:
          items:
            type: string
            format: uuid
          type: array
          title: Frame Ids
      type: object
      required:
      - stored
      - duplicates
      - frame_ids
      title: AFSFramesUploadResult
    AIFeatureQuotaView:
      properties:
        remaining:
          type: number
          title: Remaining
        capacity:
          type: number
          title: Capacity
        monthly_allowance:
          type: integer
          title: Monthly Allowance
      type: object
      required:
      - remaining
      - capacity
      - monthly_allowance
      title: AIFeatureQuotaView
      description: 'One-feature snapshot of the free-tier monthly quota.


        Emitted on /v1/me only for users on ``subscription_tier=''free''``;

        paid tiers receive ``ai_feature_quotas=None``. iOS uses ``remaining``

        to render the quota meter and decide when to surface the

        "running low — upgrade to Plus" copy.


        The bucket is a continuous token bucket internally, so ``remaining``

        is a float that recovers between calls. ``monthly_allowance`` is the

        sustained per-month refill rate × 2.592e6 seconds — the long-run

        cap a user can use per month. ``capacity`` is the upfront burst the

        bucket allows after a quiet period (catch-up after travel etc.).'
    AIPipelineSnapshot:
      properties:
        queue_pending:
          type: integer
          title: Queue Pending
        dlq_count:
          type: integer
          title: Dlq Count
        messages_in_processing:
          type: integer
          title: Messages In Processing
        messages_stuck_count:
          type: integer
          title: Messages Stuck Count
        messages_by_status_24h:
          additionalProperties:
            type: integer
          type: object
          title: Messages By Status 24H
        worker_queue_lag_p95_seconds:
          anyOf:
          - type: number
          - type: 'null'
          title: Worker Queue Lag P95 Seconds
        llm_calls_per_sec:
          anyOf:
          - type: number
          - type: 'null'
          title: Llm Calls Per Sec
        llm_4xx_per_sec:
          anyOf:
          - type: number
          - type: 'null'
          title: Llm 4Xx Per Sec
      additionalProperties: false
      type: object
      required:
      - queue_pending
      - dlq_count
      - messages_in_processing
      - messages_stuck_count
      - messages_by_status_24h
      - worker_queue_lag_p95_seconds
      - llm_calls_per_sec
      - llm_4xx_per_sec
      title: AIPipelineSnapshot
      description: 'Message-processing pipeline health.


        Sourced from Postgres (status distribution, in-processing, stuck count)

        + Redis (outbox depth / DLQ) + Cloud Monitoring (worker queue lag,

        Gemini call / 4xx rate). The old in-process histograms (stage p95,

        concurrency, reaper counts) were emitted by the *worker* process and

        aren''t visible from the api process on split Cloud Run services, so they

        are sourced from fleet-accurate signals or dropped.'
    AIProcessorInfo:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        encryption_public_key_b64:
          type: string
          title: Encryption Public Key B64
        identity_public_key_b64:
          type: string
          title: Identity Public Key B64
      type: object
      required:
      - device_id
      - encryption_public_key_b64
      - identity_public_key_b64
      title: AIProcessorInfo
      description: 'Public-only material for the workspace''s AI processor.


        Clients use this to include the AI processor as a recipient when sealing

        envelopes for Tier 1 workspaces. The encryption_public_key_b64 is the

        X25519 pubkey the wrapped session key gets encrypted to.'
    AIUsageSnapshot:
      properties:
        as_of:
          type: string
          format: date-time
          title: As Of
        free_users:
          type: integer
          title: Free Users
        total_ai_spend_micros:
          type: integer
          title: Total Ai Spend Micros
        free_users_near_budget:
          type: integer
          title: Free Users Near Budget
        free_users_over_budget:
          type: integer
          title: Free Users Over Budget
        internal_users:
          type: integer
          title: Internal Users
        timed_overrides_active:
          type: integer
          title: Timed Overrides Active
        timed_overrides_expiring_24h:
          type: integer
          title: Timed Overrides Expiring 24H
        ai_processing_consented:
          type: integer
          title: Ai Processing Consented
        budget_micros:
          type: integer
          title: Budget Micros
      type: object
      required:
      - as_of
      - free_users
      - total_ai_spend_micros
      - free_users_near_budget
      - free_users_over_budget
      - internal_users
      - timed_overrides_active
      - timed_overrides_expiring_24h
      - ai_processing_consented
      - budget_micros
      title: AIUsageSnapshot
    AcceptCallInput:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
      type: object
      required:
      - device_id
      title: AcceptCallInput
    ActionView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        message_id:
          type: string
          format: uuid
          title: Message Id
        kind:
          type: string
          title: Kind
        status:
          type: string
          title: Status
        urgency:
          type: string
          title: Urgency
        title:
          type: string
          title: Title
        when_text:
          anyOf:
          - type: string
          - type: 'null'
          title: When Text
        when_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: When At
        location:
          anyOf:
          - type: string
          - type: 'null'
          title: Location
        person_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Person Name
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
        snoozed_until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Snoozed Until
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - thread_id
      - message_id
      - kind
      - status
      - urgency
      - title
      - when_text
      - when_at
      - location
      - person_name
      - expires_at
      - snoozed_until
      - created_at
      title: ActionView
    ActionsBucket:
      properties:
        bucket:
          type: string
          title: Bucket
        label:
          type: string
          title: Label
        actions:
          items:
            $ref: '#/components/schemas/ActionView'
          type: array
          title: Actions
      type: object
      required:
      - bucket
      - label
      - actions
      title: ActionsBucket
    ActionsDebugResponse:
      properties:
        total:
          type: integer
          title: Total
        by_status:
          additionalProperties:
            type: integer
          type: object
          title: By Status
        by_urgency:
          additionalProperties:
            type: integer
          type: object
          title: By Urgency
        expired_count:
          type: integer
          title: Expired Count
        snoozed_in_future_count:
          type: integer
          title: Snoozed In Future Count
        recent:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Recent
      type: object
      required:
      - total
      - by_status
      - by_urgency
      - expired_count
      - snoozed_in_future_count
      - recent
      title: ActionsDebugResponse
      description: 'Diagnostic snapshot of the caller''s suggested_actions table state.


        Temporary diagnostic surface for the Work-tab-shows-no-actions

        investigation. Returns per-status counts plus a sample of the most

        recent rows so we can tell whether actions are (a) never created,

        (b) created but auto-expired, or (c) filtered by some other clause.'
    ActionsGroupedResponse:
      properties:
        buckets:
          items:
            $ref: '#/components/schemas/ActionsBucket'
          type: array
          title: Buckets
        total_open:
          type: integer
          title: Total Open
      type: object
      required:
      - buckets
      - total_open
      title: ActionsGroupedResponse
    AddMembersInput:
      properties:
        user_ids:
          items:
            type: string
            format: uuid
          type: array
          maxItems: 50
          minItems: 1
          title: User Ids
      type: object
      required:
      - user_ids
      title: AddMembersInput
    AgentProfileResponse:
      properties:
        identity:
          additionalProperties: true
          type: object
          title: Identity
        user_corrections:
          additionalProperties: true
          type: object
          title: User Corrections
        preferences:
          additionalProperties: true
          type: object
          title: Preferences
        identity_derived_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Identity Derived At
        preferences_derived_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Preferences Derived At
      type: object
      required:
      - identity
      - user_corrections
      - preferences
      - identity_derived_at
      - preferences_derived_at
      title: AgentProfileResponse
    AiPolicy:
      properties:
        allowed_models:
          items:
            $ref: '#/components/schemas/ModelPin'
          type: array
          title: Allowed Models
        residency:
          type: string
          enum:
          - unrestricted
          - eu_only
          - us_only
          - gcc_only
          - india_only
          title: Residency
          default: unrestricted
        capability_rules:
          items:
            $ref: '#/components/schemas/CapabilityPolicyRule'
          type: array
          title: Capability Rules
      additionalProperties: false
      type: object
      title: AiPolicy
      description: 'Mirror of the Rust `domain::ai_policy::AiPolicy`.


        The server-side check only consults `allowed_models` + `residency`

        today; capability rules are operator-portal scope (where the

        Co-Pilot lives). Future P-waves can extend the server check to

        consult capability rules if/when server-side suggestion paths

        surface to operators directly.'
    AlertEntry:
      properties:
        name:
          type: string
          title: Name
        severity:
          type: string
          title: Severity
        labels:
          additionalProperties:
            type: string
          type: object
          title: Labels
      additionalProperties: false
      type: object
      required:
      - name
      - severity
      - labels
      title: AlertEntry
    AnonDropListResponse:
      properties:
        drops:
          items:
            $ref: '#/components/schemas/AnonDropView'
          type: array
          title: Drops
      type: object
      required:
      - drops
      title: AnonDropListResponse
    AnonDropView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        ref_token:
          type: string
          title: Ref Token
        sender_display_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Sender Display Name
        audio_object_key:
          type: string
          title: Audio Object Key
        audio_duration_seconds:
          anyOf:
          - type: number
          - type: 'null'
          title: Audio Duration Seconds
        audio_size_bytes:
          type: integer
          title: Audio Size Bytes
        ai_status:
          type: string
          title: Ai Status
        ai_payload:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Ai Payload
        created_at:
          type: string
          format: date-time
          title: Created At
        claimed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Claimed At
        claim_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Claim User Id
      type: object
      required:
      - id
      - ref_token
      - sender_display_name
      - audio_object_key
      - audio_duration_seconds
      - audio_size_bytes
      - ai_status
      - ai_payload
      - created_at
      - claimed_at
      - claim_user_id
      title: AnonDropView
    AppleWebhookResponse:
      properties:
        notification_type:
          type: string
          title: Notification Type
        notification_uuid:
          type: string
          title: Notification Uuid
        handled:
          type: boolean
          title: Handled
      type: object
      required:
      - notification_type
      - notification_uuid
      - handled
      title: AppleWebhookResponse
      description: 'Apple''s webhook expects a 200 OK with empty body on success; we

        return a sentinel for diagnostics. Apple does not parse the body.'
    ApprovalRequestInput:
      properties:
        action_id:
          type: string
          format: uuid
          title: Action Id
      type: object
      required:
      - action_id
      title: ApprovalRequestInput
    ApprovalRequestView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        assistant_id:
          type: string
          format: uuid
          title: Assistant Id
        action_id:
          type: string
          format: uuid
          title: Action Id
        owner_user_id:
          type: string
          format: uuid
          title: Owner User Id
        status:
          type: string
          title: Status
        requested_payload:
          additionalProperties: true
          type: object
          title: Requested Payload
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - assistant_id
      - action_id
      - owner_user_id
      - status
      - created_at
      title: ApprovalRequestView
    ArchiveResponse:
      properties:
        archived_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Archived At
      type: object
      required:
      - archived_at
      title: ArchiveResponse
    AskByVoiceRequest:
      properties:
        audio_b64:
          type: string
          minLength: 1
          title: Audio B64
        audio_mime:
          type: string
          maxLength: 64
          title: Audio Mime
          default: audio/wav
        hint_language:
          anyOf:
          - type: string
            maxLength: 8
          - type: 'null'
          title: Hint Language
        calendar_events:
          anyOf:
          - items:
              $ref: '#/components/schemas/CalendarContextEvent'
            type: array
          - type: 'null'
          title: Calendar Events
        reminders:
          anyOf:
          - items:
              $ref: '#/components/schemas/ReminderContextItem'
            type: array
          - type: 'null'
          title: Reminders
        contacts:
          anyOf:
          - items:
              $ref: '#/components/schemas/ContactContextItem'
            type: array
          - type: 'null'
          title: Contacts
        location:
          anyOf:
          - $ref: '#/components/schemas/LocationContextItem'
          - type: 'null'
      type: object
      required:
      - audio_b64
      title: AskByVoiceRequest
      description: 'Voice-question body.


        The audio is recorded on-device, base64-encoded, and POSTed here.

        The server transcribes via Gemma-4''s multimodal endpoint (the same

        audio path that powers voice notes), then runs the transcript

        through the same agent pipeline as `/v1/ask/stream`.


        The OS-context bundles (calendar / reminders / contacts / location)

        mirror `AskRequest` so voice asks like "what''s on my calendar

        Thursday?" can reach the Phase 7/8 client-bundle tools. Without

        these the voice path silently runs against empty bundles even when

        the iOS client gathered them.'
    AskHistoryItem:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        question:
          type: string
          title: Question
        answer:
          anyOf:
          - type: string
          - type: 'null'
          title: Answer
        outcome:
          type: string
          title: Outcome
        modality:
          type: string
          title: Modality
        duration_ms:
          type: integer
          title: Duration Ms
        tool_count:
          type: integer
          title: Tool Count
        citation_count:
          type: integer
          title: Citation Count
        asked_at:
          type: string
          format: date-time
          title: Asked At
      type: object
      required:
      - id
      - question
      - answer
      - outcome
      - modality
      - duration_ms
      - tool_count
      - citation_count
      - asked_at
      title: AskHistoryItem
    AskHistoryResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/AskHistoryItem'
          type: array
          title: Items
        total:
          type: integer
          title: Total
        has_more:
          type: boolean
          title: Has More
      type: object
      required:
      - items
      - total
      - has_more
      title: AskHistoryResponse
    AskRequest:
      properties:
        question:
          type: string
          maxLength: 400
          minLength: 2
          title: Question
        context_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Context Message Id
        calendar_events:
          anyOf:
          - items:
              $ref: '#/components/schemas/CalendarContextEvent'
            type: array
          - type: 'null'
          title: Calendar Events
        reminders:
          anyOf:
          - items:
              $ref: '#/components/schemas/ReminderContextItem'
            type: array
          - type: 'null'
          title: Reminders
        contacts:
          anyOf:
          - items:
              $ref: '#/components/schemas/ContactContextItem'
            type: array
          - type: 'null'
          title: Contacts
        location:
          anyOf:
          - $ref: '#/components/schemas/LocationContextItem'
          - type: 'null'
      type: object
      required:
      - question
      title: AskRequest
    AskResponse:
      properties:
        question:
          type: string
          title: Question
        answer:
          type: string
          title: Answer
        citations:
          items:
            $ref: '#/components/schemas/Citation'
          type: array
          title: Citations
        no_data:
          type: boolean
          title: No Data
          default: false
      type: object
      required:
      - question
      - answer
      - citations
      title: AskResponse
    AssistantActionView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        assistant_id:
          type: string
          format: uuid
          title: Assistant Id
        owner_user_id:
          type: string
          format: uuid
          title: Owner User Id
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        kind:
          type: string
          title: Kind
        status:
          type: string
          title: Status
        requires_approval:
          type: boolean
          title: Requires Approval
        output:
          additionalProperties: true
          type: object
          title: Output
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - assistant_id
      - owner_user_id
      - thread_id
      - kind
      - status
      - requires_approval
      - created_at
      title: AssistantActionView
    AssistantBriefItem:
      properties:
        id:
          type: string
          title: Id
        title:
          type: string
          title: Title
        kind:
          type: string
          title: Kind
        urgency:
          type: string
          title: Urgency
        due_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Due At
      type: object
      required:
      - id
      - title
      - kind
      - urgency
      title: AssistantBriefItem
    AssistantCalendarContextEvent:
      properties:
        title:
          type: string
          maxLength: 300
          title: Title
        start:
          type: string
          format: date-time
          title: Start
        end:
          type: string
          format: date-time
          title: End
        location:
          anyOf:
          - type: string
            maxLength: 300
          - type: 'null'
          title: Location
        calendar_name:
          anyOf:
          - type: string
            maxLength: 120
          - type: 'null'
          title: Calendar Name
        is_all_day:
          type: boolean
          title: Is All Day
          default: false
        url:
          anyOf:
          - type: string
            maxLength: 500
          - type: 'null'
          title: Url
      type: object
      required:
      - title
      - start
      - end
      title: AssistantCalendarContextEvent
    AssistantClientActionCompleteInput:
      properties:
        result:
          additionalProperties: true
          type: object
          title: Result
      type: object
      title: AssistantClientActionCompleteInput
    AssistantContextInput:
      properties:
        sender_display_name:
          type: string
          maxLength: 120
          minLength: 1
          title: Sender Display Name
        is_own:
          type: boolean
          title: Is Own
          default: false
        sent_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Sent At
        kind:
          type: string
          maxLength: 32
          title: Kind
          default: text
        snippet:
          type: string
          maxLength: 480
          minLength: 1
          title: Snippet
      type: object
      required:
      - sender_display_name
      - snippet
      title: AssistantContextInput
    AssistantInvocationResult:
      properties:
        visibility:
          type: string
          title: Visibility
        run:
          $ref: '#/components/schemas/AssistantRunView'
        action:
          $ref: '#/components/schemas/AssistantActionView'
      type: object
      required:
      - visibility
      - run
      - action
      title: AssistantInvocationResult
    AssistantInvokeInput:
      properties:
        prompt:
          type: string
          maxLength: 4000
          minLength: 1
          title: Prompt
        participants:
          items:
            type: string
          type: array
          maxItems: 20
          title: Participants
        context:
          items:
            $ref: '#/components/schemas/AssistantContextInput'
          type: array
          maxItems: 50
          title: Context
        calendar_events:
          anyOf:
          - items:
              $ref: '#/components/schemas/AssistantCalendarContextEvent'
            type: array
            maxItems: 60
          - type: 'null'
          title: Calendar Events
      type: object
      required:
      - prompt
      title: AssistantInvokeInput
    AssistantPermissionInput:
      properties:
        capability:
          type: string
          maxLength: 80
          minLength: 1
          title: Capability
        level:
          type: string
          maxLength: 32
          minLength: 1
          title: Level
        limits:
          additionalProperties: true
          type: object
          title: Limits
      type: object
      required:
      - capability
      - level
      title: AssistantPermissionInput
    AssistantPermissionView:
      properties:
        capability:
          type: string
          title: Capability
        level:
          type: string
          title: Level
        limits:
          additionalProperties: true
          type: object
          title: Limits
      type: object
      required:
      - capability
      - level
      title: AssistantPermissionView
    AssistantPermissionsInput:
      properties:
        permissions:
          items:
            $ref: '#/components/schemas/AssistantPermissionInput'
          type: array
          maxItems: 50
          minItems: 0
          title: Permissions
      type: object
      required:
      - permissions
      title: AssistantPermissionsInput
    AssistantRunView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        assistant_id:
          type: string
          format: uuid
          title: Assistant Id
        owner_user_id:
          type: string
          format: uuid
          title: Owner User Id
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        visibility:
          type: string
          title: Visibility
        status:
          type: string
          title: Status
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - assistant_id
      - owner_user_id
      - thread_id
      - visibility
      - status
      - created_at
      title: AssistantRunView
    AssistantSettingsPatch:
      properties:
        name:
          anyOf:
          - type: string
            maxLength: 120
          - type: 'null'
          title: Name
        avatar_object_key:
          anyOf:
          - type: string
            maxLength: 512
          - type: 'null'
          title: Avatar Object Key
        instructions:
          anyOf:
          - type: string
            maxLength: 12000
          - type: 'null'
          title: Instructions
        enabled:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Enabled
      type: object
      title: AssistantSettingsPatch
    AssistantThreadBriefView:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        headline:
          anyOf:
          - type: string
          - type: 'null'
          title: Headline
        pending:
          items:
            $ref: '#/components/schemas/AssistantBriefItem'
          type: array
          title: Pending
        suggested_action:
          anyOf:
          - type: string
          - type: 'null'
          title: Suggested Action
      type: object
      required:
      - thread_id
      title: AssistantThreadBriefView
      description: 'Proactive "brief on open": what the owner needs to know + what''s

        pending from them in a thread, prepared by the assistant.'
    AssistantThreadInput:
      properties:
        mode:
          type: string
          maxLength: 64
          title: Mode
          default: private_suggestions
      type: object
      title: AssistantThreadInput
    AssistantThreadMembershipView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        assistant_id:
          type: string
          format: uuid
          title: Assistant Id
        owner_user_id:
          type: string
          format: uuid
          title: Owner User Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        mode:
          type: string
          title: Mode
        status:
          type: string
          title: Status
      type: object
      required:
      - id
      - assistant_id
      - owner_user_id
      - thread_id
      - mode
      - status
      title: AssistantThreadMembershipView
    AssistantView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        owner_user_id:
          type: string
          format: uuid
          title: Owner User Id
        name:
          type: string
          title: Name
        avatar_object_key:
          anyOf:
          - type: string
          - type: 'null'
          title: Avatar Object Key
        instructions:
          type: string
          title: Instructions
        enabled:
          type: boolean
          title: Enabled
        permissions:
          items:
            $ref: '#/components/schemas/AssistantPermissionView'
          type: array
          title: Permissions
      type: object
      required:
      - id
      - owner_user_id
      - name
      - instructions
      - enabled
      title: AssistantView
    AuditDrainRequest:
      properties:
        session_id:
          type: string
          maxLength: 160
          minLength: 1
          title: Session Id
        verifying_key_hex:
          type: string
          maxLength: 128
          minLength: 32
          title: Verifying Key Hex
        chain_hash_hex:
          type: string
          maxLength: 128
          minLength: 32
          title: Chain Hash Hex
        entry_count:
          type: integer
          minimum: 1.0
          title: Entry Count
        payload:
          additionalProperties: true
          type: object
          title: Payload
      additionalProperties: false
      type: object
      required:
      - session_id
      - verifying_key_hex
      - chain_hash_hex
      - entry_count
      title: AuditDrainRequest
    AuditDrainResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        chain_hash_hex:
          type: string
          title: Chain Hash Hex
        entry_count:
          type: integer
          title: Entry Count
        accepted:
          type: boolean
          title: Accepted
        audit_entry_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Audit Entry Id
      type: object
      required:
      - id
      - chain_hash_hex
      - entry_count
      - accepted
      - audit_entry_id
      title: AuditDrainResponse
    AuditEntryView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        created_at:
          type: string
          format: date-time
          title: Created At
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        actor_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Actor User Id
        action:
          type: string
          title: Action
        target_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Target Type
        target_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Target Id
        result:
          type: string
          title: Result
        details:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Details
      type: object
      required:
      - id
      - created_at
      - workspace_id
      - actor_user_id
      - action
      - target_type
      - target_id
      - result
      - details
      title: AuditEntryView
    AuditListResponse:
      properties:
        entries:
          items:
            $ref: '#/components/schemas/AuditEntryView'
          type: array
          title: Entries
      type: object
      required:
      - entries
      title: AuditListResponse
    BackfillResponse:
      properties:
        queued:
          type: integer
          title: Queued
      type: object
      required:
      - queued
      title: BackfillResponse
    BackupPutInput:
      properties:
        version:
          type: integer
          maximum: 255.0
          minimum: 1.0
          title: Version
        kdf_algo:
          type: string
          maxLength: 64
          minLength: 1
          title: Kdf Algo
        salt_b64:
          type: string
          maxLength: 128
          minLength: 1
          title: Salt B64
        ciphertext_b64:
          type: string
          maxLength: 24000
          minLength: 1
          title: Ciphertext B64
      type: object
      required:
      - version
      - kdf_algo
      - salt_b64
      - ciphertext_b64
      title: BackupPutInput
    BackupStatusView:
      properties:
        enabled:
          type: boolean
          title: Enabled
        version:
          anyOf:
          - type: integer
          - type: 'null'
          title: Version
        kdf_algo:
          anyOf:
          - type: string
          - type: 'null'
          title: Kdf Algo
        updated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Updated At
      type: object
      required:
      - enabled
      title: BackupStatusView
      description: 'Lightweight indicator for the Settings UI — does NOT include

        the ciphertext, so calling this on every Settings render is cheap

        and doesn''t force the device to download the envelope.'
    BackupView:
      properties:
        version:
          type: integer
          title: Version
        kdf_algo:
          type: string
          title: Kdf Algo
        salt_b64:
          type: string
          title: Salt B64
        ciphertext_b64:
          type: string
          title: Ciphertext B64
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - version
      - kdf_algo
      - salt_b64
      - ciphertext_b64
      - updated_at
      title: BackupView
      description: 'Returned to the client during restore. Plain bytes round-tripped

        through base64url so the JSON envelope stays text.'
    BadgeResponse:
      properties:
        total_unread:
          type: integer
          title: Total Unread
      type: object
      required:
      - total_unread
      title: BadgeResponse
      description: 'Total unread peer messages across every thread the caller belongs

        to. Used by iOS to set the app icon badge in one round-trip — no

        per-thread enumeration required.'
    BankContextResponse:
      properties:
        customer_ref:
          type: string
          title: Customer Ref
        status:
          type: string
          title: Status
        degraded:
          type: boolean
          title: Degraded
        redacted_payload:
          additionalProperties: true
          type: object
          title: Redacted Payload
        snapshot_id:
          type: string
          format: uuid
          title: Snapshot Id
        reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Reason
      type: object
      required:
      - customer_ref
      - status
      - degraded
      - redacted_payload
      - snapshot_id
      title: BankContextResponse
    BannerView:
      properties:
        id:
          type: string
          title: Id
        icon_sf:
          type: string
          title: Icon Sf
        title:
          type: string
          title: Title
        body:
          anyOf:
          - type: string
          - type: 'null'
          title: Body
        accent:
          type: string
          title: Accent
          default: blue
        primary_label:
          anyOf:
          - type: string
          - type: 'null'
          title: Primary Label
        primary_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Primary Url
        dismissable:
          type: boolean
          title: Dismissable
          default: true
      type: object
      required:
      - id
      - icon_sf
      - title
      title: BannerView
    BlockListItem:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        blocked_at:
          type: string
          format: date-time
          title: Blocked At
      type: object
      required:
      - user_id
      - display_name
      - blocked_at
      title: BlockListItem
    BlockRequest:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
      type: object
      required:
      - user_id
      title: BlockRequest
    BlocksResponse:
      properties:
        blocks:
          items:
            $ref: '#/components/schemas/BlockListItem'
          type: array
          title: Blocks
      type: object
      required:
      - blocks
      title: BlocksResponse
    Body_submit_anon_drop_a__ref_token__drop_post:
      properties:
        audio:
          type: string
          contentMediaType: application/octet-stream
          title: Audio
        display_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Display Name
        phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Phone
      type: object
      required:
      - audio
      title: Body_submit_anon_drop_a__ref_token__drop_post
    Body_verify_watermark_v1_forensics_verify_post:
      properties:
        file:
          type: string
          contentMediaType: application/octet-stream
          title: File
      type: object
      required:
      - file
      title: Body_verify_watermark_v1_forensics_verify_post
    BriefingResponse:
      properties:
        generated_at:
          type: string
          format: date-time
          title: Generated At
        threads_active:
          type: integer
          title: Threads Active
        messages_seen:
          type: integer
          title: Messages Seen
        waiting_on_you:
          type: integer
          title: Waiting On You
        you_are_waiting_on:
          type: integer
          title: You Are Waiting On
        open_attention_count:
          type: integer
          title: Open Attention Count
          default: 0
        sections:
          items:
            $ref: '#/components/schemas/BriefingSection'
          type: array
          title: Sections
          default: []
        top_threads:
          items:
            $ref: '#/components/schemas/ThreadSnippet'
          type: array
          title: Top Threads
          default: []
        overdue_tasks:
          items:
            $ref: '#/components/schemas/TaskSnippet'
          type: array
          title: Overdue Tasks
          default: []
        open_questions:
          items:
            $ref: '#/components/schemas/OpenQuestionItem'
          type: array
          title: Open Questions
          default: []
        summary:
          anyOf:
          - type: string
          - type: 'null'
          title: Summary
        follow_ups:
          items:
            type: string
          type: array
          title: Follow Ups
          default: []
        unresponded_summary:
          anyOf:
          - type: string
          - type: 'null'
          title: Unresponded Summary
        audio_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Audio Url
        audio_duration_seconds:
          anyOf:
          - type: number
          - type: 'null'
          title: Audio Duration Seconds
        audio_word_timings:
          items:
            $ref: '#/components/schemas/WordTiming'
          type: array
          title: Audio Word Timings
          default: []
      type: object
      required:
      - generated_at
      - threads_active
      - messages_seen
      - waiting_on_you
      - you_are_waiting_on
      title: BriefingResponse
    BriefingSection:
      properties:
        kind:
          type: string
          title: Kind
        title:
          type: string
          title: Title
        summary:
          anyOf:
          - type: string
          - type: 'null'
          title: Summary
        items:
          items:
            $ref: '#/components/schemas/BriefingSectionItem'
          type: array
          title: Items
          default: []
        empty_copy:
          anyOf:
          - type: string
          - type: 'null'
          title: Empty Copy
      type: object
      required:
      - kind
      - title
      title: BriefingSection
      description: 'One of the three question-anchored sections in the brief.


        ``kind`` is the load-bearing field: iOS clients dispatch on it to

        pick the icon, title localization, and item-row layout.'
    BriefingSectionItem:
      properties:
        label:
          type: string
          title: Label
        sublabel:
          anyOf:
          - type: string
          - type: 'null'
          title: Sublabel
        avatar_seed:
          anyOf:
          - type: string
          - type: 'null'
          title: Avatar Seed
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        task_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Task Id
      type: object
      required:
      - label
      title: BriefingSectionItem
      description: 'One tappable row inside a brief section.


        ``avatar_seed`` is a stable string the iOS client hashes to pick a

        Theme.Avatar palette entry — for sender-keyed rows this is the

        sender_user_id; for task-keyed rows it can be the task_id or empty

        (no avatar rendered).'
    BulkInsertRequest:
      properties:
        import_job_id:
          type: string
          format: uuid
          title: Import Job Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        messages:
          items:
            $ref: '#/components/schemas/InboundMessage'
          type: array
          maxItems: 2000
          title: Messages
      additionalProperties: false
      type: object
      required:
      - import_job_id
      - thread_id
      - messages
      title: BulkInsertRequest
    BulkInsertResponse:
      properties:
        imported:
          type: integer
          title: Imported
        skipped:
          type: integer
          title: Skipped
        thread_id:
          type: string
          format: uuid
          title: Thread Id
      additionalProperties: false
      type: object
      required:
      - imported
      - skipped
      - thread_id
      title: BulkInsertResponse
    BusinessSenderMuteInput:
      properties:
        sender_user_id:
          type: string
          format: uuid
          title: Sender User Id
        muted_until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Muted Until
          description: Exclusive upper bound. NULL = mute forever.
      type: object
      required:
      - sender_user_id
      title: BusinessSenderMuteInput
    BusinessSnapshot:
      properties:
        users_total:
          type: integer
          title: Users Total
        active_devices_24h:
          type: integer
          title: Active Devices 24H
        messages_24h:
          type: integer
          title: Messages 24H
        calls_24h:
          type: integer
          title: Calls 24H
        push_success_rate_24h:
          type: number
          title: Push Success Rate 24H
        registered_tenants:
          type: integer
          title: Registered Tenants
        avg_mos_24h:
          anyOf:
          - type: number
          - type: 'null'
          title: Avg Mos 24H
        new_devices_today:
          type: integer
          title: New Devices Today
        top_tenants:
          items:
            $ref: '#/components/schemas/TopTenant'
          type: array
          title: Top Tenants
        calls_per_hour_24h:
          items:
            type: integer
          type: array
          title: Calls Per Hour 24H
        messages_per_hour_24h:
          items:
            type: integer
          type: array
          title: Messages Per Hour 24H
      additionalProperties: false
      type: object
      required:
      - users_total
      - active_devices_24h
      - messages_24h
      - calls_24h
      - push_success_rate_24h
      - registered_tenants
      - avg_mos_24h
      - new_devices_today
      - top_tenants
      - calls_per_hour_24h
      - messages_per_hour_24h
      title: BusinessSnapshot
    CalendarContextEvent:
      properties:
        title:
          type: string
          maxLength: 300
          title: Title
        start:
          type: string
          format: date-time
          title: Start
        end:
          type: string
          format: date-time
          title: End
        location:
          anyOf:
          - type: string
            maxLength: 300
          - type: 'null'
          title: Location
        calendar_name:
          anyOf:
          - type: string
            maxLength: 120
          - type: 'null'
          title: Calendar Name
        is_all_day:
          type: boolean
          title: Is All Day
          default: false
        url:
          anyOf:
          - type: string
            maxLength: 500
          - type: 'null'
          title: Url
      type: object
      required:
      - title
      - start
      - end
      title: CalendarContextEvent
      description: 'One iOS Calendar event the client surfaces with the request.


        Phase 7a — Calendar data lives in EventKit on iOS; the server

        can''t query it directly. The client reads `EKEventStore` and

        sends a bundle of upcoming events with each Ask request when

        the user has granted Calendar access. The `list_calendar_events`

        tool reads from this bundle.


        Privacy: client only sends events for the next two weeks by

        default + caps at 60 entries. No event UUIDs cross the wire;

        fields are the natural-language facets the agent needs to

        answer "what''s on my calendar Monday."'
    CallAIProcessorView:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        encryption_public_key_b64:
          type: string
          title: Encryption Public Key B64
      type: object
      required:
      - device_id
      - encryption_public_key_b64
      title: CallAIProcessorView
    CallParticipantView:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        device_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Device Id
        display_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Display Name
        phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Phone
        status:
          type: string
          title: Status
        invited_at:
          type: string
          format: date-time
          title: Invited At
        joined_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Joined At
        left_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Left At
      type: object
      required:
      - user_id
      - device_id
      - status
      - invited_at
      - joined_at
      - left_at
      title: CallParticipantView
    CallPeerDeviceView:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        device_id:
          type: string
          format: uuid
          title: Device Id
        wavelink_noise_pub_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: Wavelink Noise Pub B64
        wavelink_noise_pub_version:
          type: integer
          title: Wavelink Noise Pub Version
          default: 1
        last_wan_host:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Wan Host
        last_wan_port:
          anyOf:
          - type: integer
          - type: 'null'
          title: Last Wan Port
        last_wan_seen_at_iso:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Wan Seen At Iso
      type: object
      required:
      - user_id
      - device_id
      title: CallPeerDeviceView
      description: 'A pre-published WaveLink Noise pubkey + WAN endpoint hint for

        one device of a call participant. Returned on POST /v1/calls so

        the initiator can start the Noise handshake AND pre-seed the

        transport''s remote endpoint without waiting for the live-notified

        call.signal pubkey + endpoint exchange — closing the cross-

        network handshake race that surfaced as "Secure audio not

        verified" pre-0091/pre-B-3.


        Multiple entries per participant are possible (multi-device users).

        The initiator races the handshake against every entry; the first

        that completes wins and the rest are dropped.


        NULL ``wavelink_noise_pub_b64`` means the device hasn''t published

        its pubkey yet (pre-0091 device, fresh install that hasn''t run the

        publish endpoint). iOS falls back to the durable call.signal pull

        exchange for those entries.


        NULL ``last_wan_host`` / ``last_wan_port`` means the device hasn''t

        published an endpoint hint yet OR the most-recent hint is older

        than the 5-minute freshness cutoff. iOS falls back to the durable

        call.signal endpoint exchange in that case.'
    CallQualityBucket:
      properties:
        label:
          type: string
          title: Label
        count:
          type: integer
          title: Count
      additionalProperties: false
      type: object
      required:
      - label
      - count
      title: CallQualityBucket
    CallQualityReport:
      properties:
        call_id:
          type: string
          format: uuid
          title: Call Id
        duration_ms:
          type: integer
          minimum: 0.0
          title: Duration Ms
        mos_x10:
          type: integer
          maximum: 50.0
          minimum: 10.0
          title: Mos X10
        rtt_ms_p50:
          type: integer
          maximum: 10000.0
          minimum: 0.0
          title: Rtt Ms P50
        rtt_ms_p95:
          type: integer
          maximum: 10000.0
          minimum: 0.0
          title: Rtt Ms P95
        jitter_ms_p95:
          type: integer
          maximum: 10000.0
          minimum: 0.0
          title: Jitter Ms P95
        loss_pct:
          type: integer
          maximum: 100.0
          minimum: 0.0
          title: Loss Pct
        packets_sent:
          type: integer
          minimum: 0.0
          title: Packets Sent
        packets_received:
          type: integer
          minimum: 0.0
          title: Packets Received
        packets_lost:
          type: integer
          minimum: 0.0
          title: Packets Lost
        plc_fills:
          type: integer
          minimum: 0.0
          title: Plc Fills
        opus_bitrate_bps:
          type: integer
          minimum: 0.0
          title: Opus Bitrate Bps
        codec:
          type: string
          maxLength: 16
          minLength: 1
          title: Codec
        path_kind:
          type: string
          enum:
          - udp
          - derp
          - ws
          - undecided
          - unknown
          - direct
          - lan
          title: Path Kind
        pcm_peak_max:
          type: integer
          maximum: 32768.0
          minimum: 0.0
          title: Pcm Peak Max
        pcm_rms_mean:
          type: integer
          minimum: 0.0
          title: Pcm Rms Mean
        pcm_clipped_samples:
          type: integer
          minimum: 0.0
          title: Pcm Clipped Samples
        spectral_flatness_mean:
          type: number
          maximum: 1.0
          minimum: 0.0
          title: Spectral Flatness Mean
        anomaly_ticks:
          type: integer
          minimum: 0.0
          title: Anomaly Ticks
        anomaly_detected:
          type: boolean
          title: Anomaly Detected
        invite_acked_ms:
          anyOf:
          - type: integer
            maximum: 300000.0
            minimum: 0.0
          - type: 'null'
          title: Invite Acked Ms
        peer_joined_ms:
          anyOf:
          - type: integer
            maximum: 600000.0
            minimum: 0.0
          - type: 'null'
          title: Peer Joined Ms
        noise_handshake_ms:
          anyOf:
          - type: integer
            maximum: 600000.0
            minimum: 0.0
          - type: 'null'
          title: Noise Handshake Ms
        first_audio_ms:
          anyOf:
          - type: integer
            maximum: 600000.0
            minimum: 0.0
          - type: 'null'
          title: First Audio Ms
        first_keepalive_ms:
          anyOf:
          - type: integer
            maximum: 600000.0
            minimum: 0.0
          - type: 'null'
          title: First Keepalive Ms
        first_decoded_audio_ms:
          anyOf:
          - type: integer
            maximum: 600000.0
            minimum: 0.0
          - type: 'null'
          title: First Decoded Audio Ms
        first_render_tick_ms:
          anyOf:
          - type: integer
            maximum: 600000.0
            minimum: 0.0
          - type: 'null'
          title: First Render Tick Ms
        first_non_silent_remote_audio_ms:
          anyOf:
          - type: integer
            maximum: 600000.0
            minimum: 0.0
          - type: 'null'
          title: First Non Silent Remote Audio Ms
      additionalProperties: false
      type: object
      required:
      - call_id
      - duration_ms
      - mos_x10
      - rtt_ms_p50
      - rtt_ms_p95
      - jitter_ms_p95
      - loss_pct
      - packets_sent
      - packets_received
      - packets_lost
      - plc_fills
      - opus_bitrate_bps
      - codec
      - path_kind
      - pcm_peak_max
      - pcm_rms_mean
      - pcm_clipped_samples
      - spectral_flatness_mean
      - anomaly_ticks
      - anomaly_detected
      title: CallQualityReport
      description: 'Per-device call-quality summary posted at call end.


        Field names match `CallQualitySummary` in iOS; the snake_case

        CodingKeys keep the wire identical. MOS is sent as `mos_x10`

        (1.0..5.0 quality × 10) so the column stays integer for cheap

        indexing — the operator portal divides by 10 before display.


        Phase 6 (2026-05-20) — added call-setup timeline fields. Stage 0

        WaveLink reliability (2026-05-21) split the ambiguous

        first_audio milestone into keepalive / decoded audio / render tick

        / non-silent remote audio. All setup fields are optional

        ms-deltas from the local engine.start moment. nil means the stage

        never reached completion (failed call, timeout, declined). Server

        feeds the non-nil values into Prometheus histograms + emits a

        ``call_setup_timing`` structured log line so Cloud Logging can

        extract log-based metrics.'
    CallQualityRowView:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        duration_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Duration Ms
        mos_x10:
          anyOf:
          - type: integer
          - type: 'null'
          title: Mos X10
        rtt_ms_p50:
          anyOf:
          - type: integer
          - type: 'null'
          title: Rtt Ms P50
        rtt_ms_p95:
          anyOf:
          - type: integer
          - type: 'null'
          title: Rtt Ms P95
        jitter_ms_p95:
          anyOf:
          - type: integer
          - type: 'null'
          title: Jitter Ms P95
        loss_pct:
          anyOf:
          - type: integer
          - type: 'null'
          title: Loss Pct
        packets_sent:
          anyOf:
          - type: integer
          - type: 'null'
          title: Packets Sent
        packets_received:
          anyOf:
          - type: integer
          - type: 'null'
          title: Packets Received
        packets_lost:
          anyOf:
          - type: integer
          - type: 'null'
          title: Packets Lost
        codec:
          anyOf:
          - type: string
          - type: 'null'
          title: Codec
        path_kind:
          anyOf:
          - type: string
          - type: 'null'
          title: Path Kind
        uploaded_at:
          type: string
          format: date-time
          title: Uploaded At
        perceptual_mos_x10:
          anyOf:
          - type: integer
          - type: 'null'
          title: Perceptual Mos X10
        server_snr_x10_db:
          anyOf:
          - type: integer
          - type: 'null'
          title: Server Snr X10 Db
        server_clipping_pct_x100:
          anyOf:
          - type: integer
          - type: 'null'
          title: Server Clipping Pct X100
        server_speech_ratio_pct:
          anyOf:
          - type: integer
          - type: 'null'
          title: Server Speech Ratio Pct
        server_spectral_flatness_x1000:
          anyOf:
          - type: integer
          - type: 'null'
          title: Server Spectral Flatness X1000
        server_score_engine:
          anyOf:
          - type: string
          - type: 'null'
          title: Server Score Engine
        server_scored_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Server Scored At
      additionalProperties: false
      type: object
      required:
      - device_id
      - duration_ms
      - mos_x10
      - rtt_ms_p50
      - rtt_ms_p95
      - jitter_ms_p95
      - loss_pct
      - packets_sent
      - packets_received
      - packets_lost
      - codec
      - path_kind
      - uploaded_at
      title: CallQualityRowView
    CallQualitySnapshot:
      properties:
        sample_size_24h:
          type: integer
          title: Sample Size 24H
        mos_distribution:
          items:
            $ref: '#/components/schemas/CallQualityBucket'
          type: array
          title: Mos Distribution
        loss_distribution:
          items:
            $ref: '#/components/schemas/CallQualityBucket'
          type: array
          title: Loss Distribution
        worst_calls:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Worst Calls
      additionalProperties: false
      type: object
      required:
      - sample_size_24h
      - mos_distribution
      - loss_distribution
      - worst_calls
      title: CallQualitySnapshot
    CallQualityView:
      properties:
        call_id:
          type: string
          format: uuid
          title: Call Id
        rows:
          items:
            $ref: '#/components/schemas/CallQualityRowView'
          type: array
          title: Rows
        aggregate_mos_x10:
          anyOf:
          - type: integer
          - type: 'null'
          title: Aggregate Mos X10
        aggregate_loss_pct:
          anyOf:
          - type: integer
          - type: 'null'
          title: Aggregate Loss Pct
        aggregate_perceptual_mos_x10:
          anyOf:
          - type: integer
          - type: 'null'
          title: Aggregate Perceptual Mos X10
        aggregate_server_clipping_pct_x100:
          anyOf:
          - type: integer
          - type: 'null'
          title: Aggregate Server Clipping Pct X100
        aggregate_server_score_engine:
          anyOf:
          - type: string
          - type: 'null'
          title: Aggregate Server Score Engine
        quality_alert:
          type: boolean
          title: Quality Alert
        quality_alert_reasons:
          items:
            type: string
          type: array
          title: Quality Alert Reasons
      additionalProperties: false
      type: object
      required:
      - call_id
      - rows
      - aggregate_mos_x10
      - aggregate_loss_pct
      - aggregate_perceptual_mos_x10
      - aggregate_server_clipping_pct_x100
      - aggregate_server_score_engine
      - quality_alert
      - quality_alert_reasons
      title: CallQualityView
      description: Aggregate per-call quality returned by GET /v1/calls/{id}/quality.
    CallSignalAck:
      properties:
        delivered:
          type: boolean
          title: Delivered
        queued:
          type: boolean
          title: Queued
          default: true
        signal_id:
          type: string
          format: uuid
          title: Signal Id
        server_seq:
          type: integer
          title: Server Seq
        expires_at:
          type: string
          format: date-time
          title: Expires At
        recipient_device_id:
          type: string
          format: uuid
          title: Recipient Device Id
      type: object
      required:
      - delivered
      - signal_id
      - server_seq
      - expires_at
      - recipient_device_id
      title: CallSignalAck
      description: 'Response for ``POST /v1/calls/{call_id}/signal``.


        ``delivered`` is true when this API replica owns a live WS

        connection for the recipient device AND the payload was queued

        onto that socket. False does NOT necessarily mean the recipient

        didn''t get the signal — in a multi-replica deployment under

        ``RedisFanoutBackend`` the recipient may be connected to a

        sibling replica, which receives the broadcast and delivers it

        even though THIS replica reports `delivered=False`. Treat the

        flag as an optimistic local-delivery hint, not a hard ack. The

        iOS client treats ``queued=True`` plus ``server_seq`` as the

        reliability contract: the receiver can pull the signal if the WS

        fast path was suspended, while the sender still retries endpoint

        signals until the Noise handshake completes. The server commits the

        inbox row before attempting fanout, so a fast-path failure returns

        ``delivered=False`` without losing the pullable signal.'
    CallSignalBody:
      properties:
        to_device_id:
          type: string
          format: uuid
          title: To Device Id
          description: Recipient device. Must be a current participant of the named call.
        client_signal_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Client Signal Id
          description: Optional idempotency key generated by the sender for this logical signal. Retries
            with the same key reuse the queued row.
        signal:
          additionalProperties: true
          type: object
          title: Signal
          description: Opaque signaling payload. Includes ``kind`` (e.g. ``endpoints``, ``v2_caps``),
            endpoint host/port/pubkey, codec capabilities, optional ``wan_host``/``wan_port`` for STUN-discovered
            reflexive addresses, and B-3.5 ``network_change`` diagnostics.
      additionalProperties: false
      type: object
      required:
      - to_device_id
      - signal
      title: CallSignalBody
      description: 'Request body for ``POST /v1/calls/{call_id}/signal`` (B-5,

        2026-05-20). Replaces the WS ``call.signal`` message kind for

        handshake-data exchange — HTTP is naturally reliable and avoids

        the silent-drop window that opens whenever the WS reconnects

        between the sender''s enqueue and the recipient''s WS being live.


        Wire-compatible with the prior WS payload''s inner fields so

        server-side fanout reuses the exact same envelope. ``signal`` is

        an opaque WebRTC blob — the server does not introspect or

        persist its contents.'
    CallSignalList:
      properties:
        signals:
          items:
            $ref: '#/components/schemas/CallSignalView'
          type: array
          title: Signals
        next_after_seq:
          type: integer
          title: Next After Seq
      additionalProperties: false
      type: object
      required:
      - signals
      - next_after_seq
      title: CallSignalList
    CallSignalView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        server_seq:
          type: integer
          title: Server Seq
        call_id:
          type: string
          format: uuid
          title: Call Id
        from_device_id:
          type: string
          format: uuid
          title: From Device Id
        from_user_id:
          type: string
          format: uuid
          title: From User Id
        signal:
          additionalProperties: true
          type: object
          title: Signal
        signal_kind:
          anyOf:
          - type: string
          - type: 'null'
          title: Signal Kind
        created_at:
          type: string
          format: date-time
          title: Created At
        expires_at:
          type: string
          format: date-time
          title: Expires At
      additionalProperties: false
      type: object
      required:
      - id
      - server_seq
      - call_id
      - from_device_id
      - from_user_id
      - signal
      - signal_kind
      - created_at
      - expires_at
      title: CallSignalView
    CallTraceEventInput:
      properties:
        event_id:
          type: string
          format: uuid
          title: Event Id
        occurred_at:
          type: string
          format: date-time
          title: Occurred At
        stage:
          type: string
          maxLength: 64
          minLength: 1
          title: Stage
        name:
          type: string
          maxLength: 96
          minLength: 1
          title: Name
        severity:
          type: string
          enum:
          - debug
          - info
          - warn
          - error
          title: Severity
          default: info
        seq:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Seq
        monotonic_ms:
          anyOf:
          - type: integer
            maximum: 86400000.0
            minimum: 0.0
          - type: 'null'
          title: Monotonic Ms
        path_kind:
          anyOf:
          - type: string
            enum:
            - lan
            - direct
            - derp
            - udp
            - ws
            - undecided
            - unknown
          - type: 'null'
          title: Path Kind
        details:
          additionalProperties: true
          type: object
          title: Details
      additionalProperties: false
      type: object
      required:
      - event_id
      - occurred_at
      - stage
      - name
      title: CallTraceEventInput
      description: 'One client-side WaveLink call lifecycle/path event.


        The client persists these in a local WAL and uploads in bounded

        batches. ``event_id`` is generated by the device and makes retries

        idempotent on ``(call_id, device_id, event_id)``.'
    CallTraceEventView:
      properties:
        event_id:
          type: string
          format: uuid
          title: Event Id
        device_id:
          type: string
          format: uuid
          title: Device Id
        occurred_at:
          type: string
          format: date-time
          title: Occurred At
        uploaded_at:
          type: string
          format: date-time
          title: Uploaded At
        stage:
          type: string
          title: Stage
        name:
          type: string
          title: Name
        severity:
          type: string
          title: Severity
        seq:
          anyOf:
          - type: integer
          - type: 'null'
          title: Seq
        monotonic_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Monotonic Ms
        path_kind:
          anyOf:
          - type: string
          - type: 'null'
          title: Path Kind
        details:
          additionalProperties: true
          type: object
          title: Details
      additionalProperties: false
      type: object
      required:
      - event_id
      - device_id
      - occurred_at
      - uploaded_at
      - stage
      - name
      - severity
      - seq
      - monotonic_ms
      - path_kind
      - details
      title: CallTraceEventView
    CallTraceUpload:
      properties:
        call_id:
          type: string
          format: uuid
          title: Call Id
        events:
          items:
            $ref: '#/components/schemas/CallTraceEventInput'
          type: array
          maxItems: 500
          minItems: 1
          title: Events
      additionalProperties: false
      type: object
      required:
      - call_id
      - events
      title: CallTraceUpload
    CallTraceView:
      properties:
        call_id:
          type: string
          format: uuid
          title: Call Id
        events:
          items:
            $ref: '#/components/schemas/CallTraceEventView'
          type: array
          title: Events
      additionalProperties: false
      type: object
      required:
      - call_id
      - events
      title: CallTraceView
    CallView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        initiator_user_id:
          type: string
          format: uuid
          title: Initiator User Id
        initiator_display_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Initiator Display Name
        initiator_phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Initiator Phone
        status:
          type: string
          title: Status
        started_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Started At
        ended_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Ended At
        summary_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Summary Message Id
        ai_processor:
          anyOf:
          - $ref: '#/components/schemas/CallAIProcessorView'
          - type: 'null'
        participants:
          items:
            $ref: '#/components/schemas/CallParticipantView'
          type: array
          title: Participants
        peer_devices:
          items:
            $ref: '#/components/schemas/CallPeerDeviceView'
          type: array
          title: Peer Devices
          default: []
        force_relay:
          type: boolean
          title: Force Relay
          default: false
        relay_endpoints:
          items:
            type: string
          type: array
          title: Relay Endpoints
          default: []
      type: object
      required:
      - id
      - workspace_id
      - thread_id
      - initiator_user_id
      - status
      - started_at
      - ended_at
      - summary_message_id
      - participants
      title: CallView
    CanonicalListenbackTokenView:
      properties:
        token:
          type: string
          title: Token
        capability:
          type: string
          title: Capability
        capability_id:
          type: string
          format: uuid
          title: Capability Id
        expires_at:
          type: string
          format: date-time
          title: Expires At
      type: object
      required:
      - token
      - capability
      - capability_id
      - expires_at
      title: CanonicalListenbackTokenView
      description: Response payload for the listen-back token endpoint.
    CapabilityPolicyRule:
      properties:
        action_kind:
          type: string
          title: Action Kind
        min_signal_score:
          type: number
          maximum: 1.0
          minimum: 0.0
          title: Min Signal Score
      additionalProperties: false
      type: object
      required:
      - action_kind
      - min_signal_score
      title: CapabilityPolicyRule
    CaptureEventRequest:
      properties:
        kind:
          type: string
          title: Kind
        thread_id:
          type: string
          format: uuid
          title: Thread Id
      type: object
      required:
      - kind
      - thread_id
      title: CaptureEventRequest
      description: "Body for POST /v1/messages/{id}/capture-event.\n\nRecorded by the recipient device\
        \ when the user takes a screenshot or\nstarts screen-recording while the thread is foregrounded.\
        \ The server\naudits the event + pushes the sender so they can see who captured\ntheir content.\n\
        \n`kind` values:\n    screenshot       — UIApplication.userDidTakeScreenshotNotification\n   \
        \ screen_recording — UIScreen.capturedDidChangeNotification (started)"
    CaseActionRequest:
      properties:
        kind:
          type: string
          maxLength: 80
          minLength: 1
          title: Kind
        requires_approval:
          type: boolean
          title: Requires Approval
          default: false
        evidence:
          additionalProperties: true
          type: object
          title: Evidence
      additionalProperties: false
      type: object
      required:
      - kind
      title: CaseActionRequest
    CaseActionStatus:
      type: string
      enum:
      - proposed
      - pending_approval
      - approved
      - rejected
      - executed
      - cancelled
      title: CaseActionStatus
    CaseActionView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        kind:
          type: string
          title: Kind
        status:
          $ref: '#/components/schemas/CaseActionStatus'
        requires_approval:
          type: boolean
          title: Requires Approval
        evidence:
          additionalProperties: true
          type: object
          title: Evidence
        approved_by_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Approved By User Id
        executed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Executed At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - kind
      - status
      - requires_approval
      - evidence
      - approved_by_user_id
      - executed_at
      - created_at
      title: CaseActionView
    CaseCreateRequest:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        customer_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Customer User Id
        customer_ref:
          type: string
          maxLength: 160
          minLength: 1
          title: Customer Ref
        vertical:
          $ref: '#/components/schemas/CaseVertical'
        priority:
          $ref: '#/components/schemas/CasePriority'
          default: normal
        risk_tier:
          $ref: '#/components/schemas/CaseRiskTier'
          default: low
        queue:
          type: string
          maxLength: 80
          minLength: 1
          title: Queue
          default: default
        owner_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Owner User Id
        sla_deadline:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Sla Deadline
      additionalProperties: false
      type: object
      required:
      - thread_id
      - customer_ref
      - vertical
      title: CaseCreateRequest
    CaseDetailResponse:
      properties:
        case:
          $ref: '#/components/schemas/CaseView'
        events:
          items:
            $ref: '#/components/schemas/CaseEventView'
          type: array
          title: Events
        actions:
          items:
            $ref: '#/components/schemas/CaseActionView'
          type: array
          title: Actions
      type: object
      required:
      - case
      - events
      - actions
      title: CaseDetailResponse
    CaseEventView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        event_type:
          type: string
          title: Event Type
        actor_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Actor User Id
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        audit_entry_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Audit Entry Id
        payload:
          additionalProperties: true
          type: object
          title: Payload
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - event_type
      - actor_user_id
      - message_id
      - audit_entry_id
      - payload
      - created_at
      title: CaseEventView
    CasePriority:
      type: string
      enum:
      - low
      - normal
      - high
      - urgent
      title: CasePriority
    CaseRiskTier:
      type: string
      enum:
      - low
      - medium
      - high
      - critical
      title: CaseRiskTier
    CaseStatus:
      type: string
      enum:
      - open
      - pending_customer
      - pending_approval
      - escalated
      - resolved
      - closed
      title: CaseStatus
    CaseVertical:
      type: string
      enum:
      - complaints_service
      - fraud_disputes
      - relationship_manager
      title: CaseVertical
    CaseView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        customer_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Customer User Id
        customer_ref:
          type: string
          title: Customer Ref
        vertical:
          $ref: '#/components/schemas/CaseVertical'
        status:
          $ref: '#/components/schemas/CaseStatus'
        priority:
          $ref: '#/components/schemas/CasePriority'
        risk_tier:
          $ref: '#/components/schemas/CaseRiskTier'
        owner_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Owner User Id
        queue:
          type: string
          title: Queue
        sla_deadline:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Sla Deadline
        opened_at:
          type: string
          format: date-time
          title: Opened At
        closed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Closed At
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - id
      - workspace_id
      - thread_id
      - customer_user_id
      - customer_ref
      - vertical
      - status
      - priority
      - risk_tier
      - owner_user_id
      - queue
      - sla_deadline
      - opened_at
      - closed_at
      - created_at
      - updated_at
      title: CaseView
    Citation:
      properties:
        kind:
          type: string
          title: Kind
        memory_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Memory Id
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        person_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Person Id
        call_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Call Id
        snippet:
          type: string
          title: Snippet
        score:
          anyOf:
          - type: number
          - type: 'null'
          title: Score
      type: object
      required:
      - kind
      - snippet
      title: Citation
    ClaimedDropListResponse:
      properties:
        drops:
          items:
            $ref: '#/components/schemas/ClaimedDropView'
          type: array
          title: Drops
      type: object
      required:
      - drops
      title: ClaimedDropListResponse
    ClaimedDropView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        ref_token:
          type: string
          title: Ref Token
        inviter_user_id:
          type: string
          format: uuid
          title: Inviter User Id
        audio_object_key:
          type: string
          title: Audio Object Key
        audio_size_bytes:
          type: integer
          title: Audio Size Bytes
        audio_duration_seconds:
          anyOf:
          - type: number
          - type: 'null'
          title: Audio Duration Seconds
        ai_payload:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Ai Payload
        created_at:
          type: string
          format: date-time
          title: Created At
        claimed_at:
          type: string
          format: date-time
          title: Claimed At
      type: object
      required:
      - id
      - ref_token
      - inviter_user_id
      - audio_object_key
      - audio_size_bytes
      - audio_duration_seconds
      - ai_payload
      - created_at
      - claimed_at
      title: ClaimedDropView
    CommandBar:
      properties:
        system_status:
          type: string
          title: System Status
        system_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: System Reason
        active_calls:
          type: integer
          title: Active Calls
        active_devices_5m:
          type: integer
          title: Active Devices 5M
        messages_last_hour:
          type: integer
          title: Messages Last Hour
        firing_alerts:
          type: integer
          title: Firing Alerts
        online_websockets:
          type: integer
          title: Online Websockets
      additionalProperties: false
      type: object
      required:
      - system_status
      - system_reason
      - active_calls
      - active_devices_5m
      - messages_last_hour
      - firing_alerts
      - online_websockets
      title: CommandBar
    ComplianceSnapshot:
      properties:
        as_of:
          type: string
          format: date-time
          title: As Of
        window:
          type: string
          title: Window
        subpoenas_by_status:
          additionalProperties:
            type: integer
          type: object
          title: Subpoenas By Status
        subpoenas_overdue:
          type: integer
          title: Subpoenas Overdue
        legal_holds_active:
          type: integer
          title: Legal Holds Active
        legal_holds_expiring_7d:
          type: integer
          title: Legal Holds Expiring 7D
        retention_policies:
          type: integer
          title: Retention Policies
        workspaces_without_policy:
          type: integer
          title: Workspaces Without Policy
        webhook_endpoints_active:
          type: integer
          title: Webhook Endpoints Active
        webhook_deliveries_window:
          type: integer
          title: Webhook Deliveries Window
        webhook_failures_window:
          type: integer
          title: Webhook Failures Window
        break_glass_active:
          type: integer
          title: Break Glass Active
        break_glass_window:
          type: integer
          title: Break Glass Window
        abuse_exhausted_by_action:
          additionalProperties:
            type: integer
          type: object
          title: Abuse Exhausted By Action
      type: object
      required:
      - as_of
      - window
      - subpoenas_by_status
      - subpoenas_overdue
      - legal_holds_active
      - legal_holds_expiring_7d
      - retention_policies
      - workspaces_without_policy
      - webhook_endpoints_active
      - webhook_deliveries_window
      - webhook_failures_window
      - break_glass_active
      - break_glass_window
      - abuse_exhausted_by_action
      title: ComplianceSnapshot
    ConfirmActionRequest:
      properties:
        token:
          type: string
          title: Token
      type: object
      required:
      - token
      title: ConfirmActionRequest
    ConfirmActionResponse:
      properties:
        ok:
          type: boolean
          title: Ok
        kind:
          type: string
          title: Kind
        target_resource_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Target Resource Id
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
      type: object
      required:
      - ok
      - kind
      - target_resource_id
      title: ConfirmActionResponse
    ConsentRequest:
      properties:
        transport_e2e_acknowledged:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Transport E2E Acknowledged
        ai_processing:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Ai Processing
        ai_training_on_free_tier:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Ai Training On Free Tier
      type: object
      title: ConsentRequest
      description: 'Body for POST /v1/me/consent. All fields optional; only fields

        present in the request are mutated. Each field is independently

        grantable / revocable.'
    ConsentResponse:
      properties:
        transport_e2e_acknowledged_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Transport E2E Acknowledged At
        ai_processing_consent_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Ai Processing Consent At
        ai_training_consent_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Ai Training Consent At
        subscription_tier:
          type: string
          title: Subscription Tier
      type: object
      required:
      - transport_e2e_acknowledged_at
      - ai_processing_consent_at
      - ai_training_consent_at
      - subscription_tier
      title: ConsentResponse
    ContactContextItem:
      properties:
        name:
          type: string
          maxLength: 300
          title: Name
        phones:
          items:
            type: string
          type: array
          maxItems: 10
          title: Phones
        emails:
          items:
            type: string
          type: array
          maxItems: 10
          title: Emails
        org:
          anyOf:
          - type: string
            maxLength: 300
          - type: 'null'
          title: Org
      type: object
      required:
      - name
      title: ContactContextItem
      description: Phase 8 — iOS Contacts bundle entry.
    ContinuityHighlight:
      properties:
        text:
          type: string
          title: Text
        kind:
          type: string
          title: Kind
        person_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Person Name
        occurred_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Occurred At
      type: object
      required:
      - text
      - kind
      title: ContinuityHighlight
      description: A single recent memory worth surfacing before the user replies.
    ContinuityResponse:
      properties:
        should_show:
          type: boolean
          title: Should Show
        hours_since_last_message:
          anyOf:
          - type: number
          - type: 'null'
          title: Hours Since Last Message
        peer_display_names:
          items:
            type: string
          type: array
          title: Peer Display Names
        highlights:
          items:
            $ref: '#/components/schemas/ContinuityHighlight'
          type: array
          title: Highlights
        suggestion:
          anyOf:
          - type: string
          - type: 'null'
          title: Suggestion
      type: object
      required:
      - should_show
      - hours_since_last_message
      - peer_display_names
      - highlights
      title: ContinuityResponse
      description: 'GET /v1/threads/{id}/continuity — context the user might want before

        they reply to a peer they haven''t talked to in a while.


        The iOS thread view fetches this on appear. When `should_show=true` it

        surfaces a small pill above the composer ("Last time, Sarah mentioned

        her mom was sick — worth checking in?"). When `should_show=false` (no

        silence, no useful highlights, or self thread), the pill stays hidden.


        The server decides "should_show" so iOS doesn''t need to embed the

        silence-threshold heuristic — and we can tune it (24h? 72h?) without

        shipping an app update.'
    CreateImportJobRequest:
      properties:
        source:
          type: string
          maxLength: 32
          minLength: 1
          title: Source
        total_messages:
          type: integer
          minimum: 1.0
          title: Total Messages
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
      type: object
      required:
      - source
      - total_messages
      title: CreateImportJobRequest
    CreateImportJobResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        status:
          type: string
          title: Status
      additionalProperties: false
      type: object
      required:
      - id
      - status
      title: CreateImportJobResponse
    CreateTaskRequest:
      properties:
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        title:
          type: string
          title: Title
        due_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Due At
        priority:
          type: string
          title: Priority
          default: medium
      type: object
      required:
      - workspace_id
      - title
      title: CreateTaskRequest
    CrossCallEntityView:
      properties:
        label:
          type: string
          title: Label
        mention_count:
          type: integer
          title: Mention Count
        call_ids:
          items:
            type: string
            format: uuid
          type: array
          title: Call Ids
        first_seen_at:
          type: string
          format: date-time
          title: First Seen At
        last_seen_at:
          type: string
          format: date-time
          title: Last Seen At
      type: object
      required:
      - label
      - mention_count
      - call_ids
      - first_seen_at
      - last_seen_at
      title: CrossCallEntityView
      description: 'One recurring entity / topic that surfaced across multiple

        calls (Creative B).


        The cluster is a greedy cosine-similarity bucket on call-grounded

        memory items — we don''t run a real clustering algorithm here;

        the volume is small enough that pairwise neighbour-merging is

        cheap and stable. Output is the most-recent memory text as the

        label, the count of mentions, and the distinct call ids.'
    DailySummaryView:
      properties:
        lookback_hours:
          type: integer
          title: Lookback Hours
        runs:
          type: integer
          title: Runs
        created:
          type: integer
          title: Created
        queued:
          type: integer
          title: Queued
        hidden:
          type: integer
          title: Hidden
        deduped:
          type: integer
          title: Deduped
        extraction_enabled:
          type: boolean
          title: Extraction Enabled
      type: object
      required:
      - lookback_hours
      - runs
      - created
      - queued
      - hidden
      - deduped
      - extraction_enabled
      title: DailySummaryView
      description: 'Per-user agent activity digest for the iOS Work-tab footer line.


        A subtle one-liner above the Tasks segment ("Today: 6 created · 4

        hidden · 2 deduped") that surfaces the agent''s invisible work

        without being noisy. Empty / all-zeros payload renders nothing on

        iOS; the view-model checks each count.'
    DeleteMeInput:
      properties:
        confirm_text:
          type: string
          maxLength: 200
          minLength: 1
          title: Confirm Text
      type: object
      required:
      - confirm_text
      title: DeleteMeInput
    DeleteMeOutput:
      properties:
        deleted:
          type: boolean
          title: Deleted
        workspace_ids_deleted:
          items:
            type: string
            format: uuid
          type: array
          title: Workspace Ids Deleted
      type: object
      required:
      - deleted
      - workspace_ids_deleted
      title: DeleteMeOutput
    DenyActionRequest:
      properties:
        token:
          type: string
          title: Token
      type: object
      required:
      - token
      title: DenyActionRequest
    DeviceListResponse:
      properties:
        devices:
          items:
            $ref: '#/components/schemas/DeviceView'
          type: array
          title: Devices
      type: object
      required:
      - devices
      title: DeviceListResponse
    DeviceView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        label:
          type: string
          title: Label
        platform:
          type: string
          title: Platform
        created_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Created At
        last_seen_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Seen At
        is_current:
          type: boolean
          title: Is Current
          default: false
        encryption_public_key_fingerprint:
          type: string
          title: Encryption Public Key Fingerprint
          default: ''
      type: object
      required:
      - id
      - label
      - platform
      title: DeviceView
    DevicesSnapshot:
      properties:
        as_of:
          type: string
          format: date-time
          title: As Of
        devices_total:
          type: integer
          title: Devices Total
        by_platform:
          additionalProperties:
            type: integer
          type: object
          title: By Platform
        active_24h:
          type: integer
          title: Active 24H
        dormant_30d:
          type: integer
          title: Dormant 30D
        revoked_total:
          type: integer
          title: Revoked Total
        push_ready:
          type: integer
          title: Push Ready
        push_invalid:
          type: integer
          title: Push Invalid
        voip_ready:
          type: integer
          title: Voip Ready
        voip_invalid:
          type: integer
          title: Voip Invalid
      type: object
      required:
      - as_of
      - devices_total
      - by_platform
      - active_24h
      - dormant_30d
      - revoked_total
      - push_ready
      - push_invalid
      - voip_ready
      - voip_invalid
      title: DevicesSnapshot
    DirectoryEntryOut:
      properties:
        fingerprint_hex:
          type: string
          title: Fingerprint Hex
        display_name:
          type: string
          title: Display Name
        region:
          type: string
          title: Region
        homeserver_url:
          type: string
          title: Homeserver Url
        identity_pubkey_hex:
          type: string
          title: Identity Pubkey Hex
        routing_mode:
          type: string
          title: Routing Mode
        transparency_log_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Transparency Log Url
        transparency_inclusion_proof_hex:
          anyOf:
          - type: string
          - type: 'null'
          title: Transparency Inclusion Proof Hex
        directory_signature_hex:
          type: string
          title: Directory Signature Hex
        status:
          type: string
          title: Status
        enrolled_at:
          type: string
          format: date-time
          title: Enrolled At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - fingerprint_hex
      - display_name
      - region
      - homeserver_url
      - identity_pubkey_hex
      - routing_mode
      - transparency_log_url
      - transparency_inclusion_proof_hex
      - directory_signature_hex
      - status
      - enrolled_at
      - updated_at
      title: DirectoryEntryOut
      description: 'One row of the public directory. Hex-encoded for transport

        so the JSON response is grep-able + cacheable; clients re-decode

        to bytes for verification.'
    DirectoryListResponse:
      properties:
        entries:
          items:
            $ref: '#/components/schemas/DirectoryEntryOut'
          type: array
          title: Entries
        total:
          type: integer
          title: Total
      additionalProperties: false
      type: object
      required:
      - entries
      - total
      title: DirectoryListResponse
      description: 'Paginated wrapper around `entries`. v0.1 returns the entire

        list (the directory will fit in a single response for the

        foreseeable future); the wrapper exists so a future cursor /

        page-size implementation doesn''t break the wire shape.'
    DirectoryRegisterRequest:
      properties:
        fingerprint_hex:
          type: string
          maxLength: 64
          minLength: 64
          title: Fingerprint Hex
        display_name:
          type: string
          maxLength: 200
          minLength: 1
          title: Display Name
        region:
          type: string
          maxLength: 32
          minLength: 1
          title: Region
        homeserver_url:
          type: string
          minLength: 1
          title: Homeserver Url
        identity_pubkey_hex:
          type: string
          maxLength: 64
          minLength: 64
          title: Identity Pubkey Hex
        routing_mode:
          type: string
          title: Routing Mode
        transparency_log_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Transparency Log Url
        transparency_inclusion_proof_hex:
          anyOf:
          - type: string
          - type: 'null'
          title: Transparency Inclusion Proof Hex
      additionalProperties: false
      type: object
      required:
      - fingerprint_hex
      - display_name
      - region
      - homeserver_url
      - identity_pubkey_hex
      - routing_mode
      title: DirectoryRegisterRequest
      description: 'Admin payload to register a new tenant. The directory

        signature is server-computed; the caller never supplies it.'
    DirectoryRegisterResponse:
      properties:
        entry:
          $ref: '#/components/schemas/DirectoryEntryOut'
      additionalProperties: false
      type: object
      required:
      - entry
      title: DirectoryRegisterResponse
    DirectoryStatusUpdateRequest:
      properties:
        status:
          type: string
          title: Status
          description: 'Target status: ''active'' | ''suspended'' | ''revoked''.'
        reason:
          anyOf:
          - type: string
            maxLength: 500
          - type: 'null'
          title: Reason
          description: Free-text reason; surfaced in the audit trail.
      additionalProperties: false
      type: object
      required:
      - status
      title: DirectoryStatusUpdateRequest
      description: 'Admin payload for tenant lifecycle changes — suspend / revoke

        / reactivate. The status transition rules are loose in v0.1: any

        valid status is reachable from any other so a misclick is

        recoverable. The audit chain records every transition so a

        history exists even if the table only stores the latest state.'
    DirectoryVerifyingKeyResponse:
      properties:
        verifying_key_hex:
          type: string
          title: Verifying Key Hex
        fingerprint_hex:
          type: string
          title: Fingerprint Hex
        canonical_format_version:
          type: integer
          title: Canonical Format Version
          default: 1
      additionalProperties: false
      type: object
      required:
      - verifying_key_hex
      - fingerprint_hex
      title: DirectoryVerifyingKeyResponse
      description: 'Public information clients pin against to verify directory

        signatures. The pubkey is 32 bytes hex; the fingerprint is the

        SHA-256 of the pubkey bytes (handy for "is this the key I think

        it is?" comparisons in UI).'
    DisappearingRequest:
      properties:
        seconds:
          anyOf:
          - type: integer
          - type: 'null'
          title: Seconds
      type: object
      title: DisappearingRequest
      description: 'seconds=null disables disappearing; otherwise every NEW message in

        this thread expires after the given window. Reasonable presets the

        iOS UI exposes: 1h, 24h, 7d, 30d. Past messages are NOT retroactively

        stamped — that would surprise users and is hard to revert.'
    DisappearingResponse:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        disappearing_after_seconds:
          anyOf:
          - type: integer
          - type: 'null'
          title: Disappearing After Seconds
      type: object
      required:
      - thread_id
      - disappearing_after_seconds
      title: DisappearingResponse
    EffectiveCap:
      properties:
        burst:
          type: number
          title: Burst
        monthly:
          type: integer
          title: Monthly
      additionalProperties: false
      type: object
      required:
      - burst
      - monthly
      title: EffectiveCap
      description: 'Computed view of what the user actually gets after merge —

        burst + monthly for each feature. Returned in GET responses so the

        admin can verify the override does what they expect.'
    EffectiveFlagsResponse:
      properties:
        workspace_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Workspace Id
        env:
          type: string
          title: Env
        flags:
          additionalProperties:
            type: boolean
          type: object
          title: Flags
      type: object
      required:
      - workspace_id
      - env
      - flags
      title: EffectiveFlagsResponse
      description: The full effective-flag map for the caller's workspace + env.
    EffectiveFlagsWithProvenanceResponse:
      properties:
        workspace_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Workspace Id
        env:
          type: string
          title: Env
        flags:
          additionalProperties:
            $ref: '#/components/schemas/FlagProvenanceView'
          type: object
          title: Flags
      type: object
      required:
      - workspace_id
      - env
      - flags
      title: EffectiveFlagsWithProvenanceResponse
      description: 'Same scope as ``EffectiveFlagsResponse`` but every flag

        carries the row metadata an operator console needs.'
    EnvelopeRecipientWire:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        wrapped_key:
          type: string
          title: Wrapped Key
          description: base64url-encoded wrapped session key
      type: object
      required:
      - device_id
      - wrapped_key
      title: EnvelopeRecipientWire
      description: One recipient slot inside an inbound envelope from the client.
    EnvelopeWire:
      properties:
        version:
          type: integer
          title: Version
        sender_device_id:
          type: string
          format: uuid
          title: Sender Device Id
        sender_eph_public:
          type: string
          title: Sender Eph Public
        aad:
          type: string
          title: Aad
        ciphertext:
          type: string
          title: Ciphertext
        nonce:
          type: string
          title: Nonce
        signature:
          type: string
          title: Signature
        recipients:
          items:
            $ref: '#/components/schemas/EnvelopeRecipientWire'
          type: array
          title: Recipients
      type: object
      required:
      - version
      - sender_device_id
      - sender_eph_public
      - aad
      - ciphertext
      - nonce
      - signature
      - recipients
      title: EnvelopeWire
      description: 'Inbound envelope from the client over HTTP.


        Bytes are base64url-encoded so the JSON stays compact and URL-safe.'
    ExchangeRequest:
      properties:
        magic_token:
          type: string
          maxLength: 4096
          minLength: 20
          title: Magic Token
      additionalProperties: false
      type: object
      required:
      - magic_token
      title: ExchangeRequest
    ExchangeResponse:
      properties:
        session_token:
          type: string
          title: Session Token
        email:
          type: string
          title: Email
        expires_at:
          type: string
          format: date-time
          title: Expires At
      additionalProperties: false
      type: object
      required:
      - session_token
      - email
      - expires_at
      title: ExchangeResponse
    ExportCreateRequest:
      properties:
        report_kind:
          type: string
          maxLength: 80
          minLength: 1
          title: Report Kind
        case_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Case Id
        date_range_start:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Date Range Start
        date_range_end:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Date Range End
      additionalProperties: false
      type: object
      required:
      - report_kind
      title: ExportCreateRequest
    ExportPayload:
      properties:
        schema_version:
          type: string
          title: Schema Version
          default: '1'
        exported_at:
          type: string
          format: date-time
          title: Exported At
        profile:
          additionalProperties: true
          type: object
          title: Profile
        workspaces:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Workspaces
        threads:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Threads
        messages:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Messages
        tasks:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Tasks
        memory_items:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Memory Items
        people:
          items:
            additionalProperties: true
            type: object
          type: array
          title: People
      type: object
      required:
      - exported_at
      - profile
      - workspaces
      - threads
      - messages
      - tasks
      - memory_items
      - people
      title: ExportPayload
      description: 'The shape of GET /v1/me/export. Plain JSON for v0 — no audio, no

        encrypted blobs. The transcripts and summaries already live unencrypted

        in `messages.ai_payload` for Tier-1 workspaces, which is the layer the

        user actually thinks of as their data.'
    ExportStatus:
      type: string
      enum:
      - pending
      - ready
      - failed
      title: ExportStatus
    ExtractionBlockListResponse:
      properties:
        senders:
          items:
            $ref: '#/components/schemas/ExtractionBlockSenderView'
          type: array
          title: Senders
      type: object
      required:
      - senders
      title: ExtractionBlockListResponse
    ExtractionBlockSenderView:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        blocked_since:
          type: string
          format: date-time
          title: Blocked Since
      type: object
      required:
      - user_id
      - display_name
      - blocked_since
      title: ExtractionBlockSenderView
      description: 'One muted sender, with display info for the Settings summary surface

        ("AI extraction by sender").'
    ExtractionBlockToggleRequest:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        blocked:
          type: boolean
          title: Blocked
      type: object
      required:
      - user_id
      - blocked
      title: ExtractionBlockToggleRequest
    FeatureCapSpec:
      properties:
        burst:
          anyOf:
          - type: number
            maximum: 10000.0
            minimum: 1.0
          - type: 'null'
          title: Burst
        monthly:
          anyOf:
          - type: integer
            maximum: 1000000.0
            minimum: 1.0
          - type: 'null'
          title: Monthly
      additionalProperties: false
      type: object
      title: FeatureCapSpec
      description: 'One feature''s override slice. Both fields optional — supply just

        ``burst`` to override only the burst capacity, just ``monthly`` to

        override only the steady-state cap, or both.'
    FlagAuditRow:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        flag_name:
          type: string
          title: Flag Name
        workspace_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Workspace Id
        previous_enabled:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Previous Enabled
        new_enabled:
          type: boolean
          title: New Enabled
        set_by_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Set By User Id
        reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Reason
        occurred_at:
          type: string
          format: date-time
          title: Occurred At
        env:
          anyOf:
          - type: string
          - type: 'null'
          title: Env
      type: object
      required:
      - id
      - flag_name
      - workspace_id
      - previous_enabled
      - new_enabled
      - set_by_user_id
      - reason
      - occurred_at
      - env
      title: FlagAuditRow
      description: One row from ``feature_flag_audit``.
    FlagFlipRequest:
      properties:
        name:
          type: string
          maxLength: 64
          minLength: 1
          title: Name
        enabled:
          type: boolean
          title: Enabled
        workspace_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Workspace Id
        reason:
          anyOf:
          - type: string
            maxLength: 280
          - type: 'null'
          title: Reason
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
        env:
          anyOf:
          - type: string
            maxLength: 16
          - type: 'null'
          title: Env
        rollout_percentage:
          anyOf:
          - type: integer
            maximum: 100.0
            minimum: 0.0
          - type: 'null'
          title: Rollout Percentage
      additionalProperties: false
      type: object
      required:
      - name
      - enabled
      title: FlagFlipRequest
      description: 'One flag flip. ``workspace_id=None`` means flip the global

        row; passing a workspace id scopes the flip to that one. The

        actor is implicit (the authenticated caller); the resolver

        layer enforces precedence.'
    FlagProvenanceView:
      properties:
        enabled:
          type: boolean
          title: Enabled
        source:
          type: string
          title: Source
        set_by_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Set By User Id
        reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Reason
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
        set_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Set At
      type: object
      required:
      - enabled
      - source
      title: FlagProvenanceView
      description: Wire shape for one flag's provenance — VD-OPS-003.
    ForensicsVerifyResponse:
      properties:
        matched:
          type: boolean
          title: Matched
        watermark_hex:
          type: string
          title: Watermark Hex
          default: ''
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        sender_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Sender User Id
        sender_display_name:
          type: string
          title: Sender Display Name
          default: ''
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        server_received_at:
          type: string
          title: Server Received At
          default: ''
        recipient_count:
          type: integer
          title: Recipient Count
          default: 0
        reason:
          type: string
          title: Reason
          default: ''
      type: object
      required:
      - matched
      title: ForensicsVerifyResponse
      description: 'The decoded watermark + everything we know about the message it

        references — but only when the caller is authorized to see that data.'
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    HandoffEventIn:
      properties:
        kind:
          type: string
          title: Kind
        duration_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Duration Ms
        occurred_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Occurred At
      type: object
      required:
      - kind
      title: HandoffEventIn
      description: Request body for POST. Caller-supplied event metadata.
    HandoffEventView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        message_id:
          type: string
          format: uuid
          title: Message Id
        recipient_user_id:
          type: string
          format: uuid
          title: Recipient User Id
        kind:
          type: string
          title: Kind
        duration_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Duration Ms
        occurred_at:
          type: string
          format: date-time
          title: Occurred At
        received_at:
          type: string
          format: date-time
          title: Received At
      type: object
      required:
      - id
      - message_id
      - recipient_user_id
      - kind
      - duration_ms
      - occurred_at
      - received_at
      title: HandoffEventView
      description: Response shape for both POST and GET.
    HandoffEventsListResponse:
      properties:
        message_id:
          type: string
          format: uuid
          title: Message Id
        events:
          items:
            $ref: '#/components/schemas/HandoffEventView'
          type: array
          title: Events
      type: object
      required:
      - message_id
      - events
      title: HandoffEventsListResponse
    ImportJobListView:
      properties:
        jobs:
          items:
            $ref: '#/components/schemas/ImportJobView'
          type: array
          title: Jobs
        next_cursor:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Next Cursor
      additionalProperties: false
      type: object
      required:
      - jobs
      - next_cursor
      title: ImportJobListView
    ImportJobView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        user_id:
          type: string
          format: uuid
          title: User Id
        status:
          type: string
          title: Status
        source:
          type: string
          title: Source
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        total_messages:
          type: integer
          title: Total Messages
        imported_messages:
          type: integer
          title: Imported Messages
        failed_messages:
          type: integer
          title: Failed Messages
        error_message:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Message
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      additionalProperties: false
      type: object
      required:
      - id
      - workspace_id
      - user_id
      - status
      - source
      - thread_id
      - total_messages
      - imported_messages
      - failed_messages
      - error_message
      - created_at
      - updated_at
      title: ImportJobView
    InboundMessage:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        client_message_id:
          type: string
          maxLength: 64
          minLength: 1
          title: Client Message Id
        content_type:
          type: string
          pattern: ^(text|voice|image|file|location)$
          title: Content Type
        envelope:
          $ref: '#/components/schemas/EnvelopeWire'
        media_object_key:
          anyOf:
          - type: string
          - type: 'null'
          title: Media Object Key
        media_size_bytes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Media Size Bytes
        reply_to_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Reply To Message Id
        forwarded_from_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Forwarded From Message Id
        supersedes_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Supersedes Message Id
        historical_timestamp:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Historical Timestamp
        external_sender_name:
          anyOf:
          - type: string
            maxLength: 120
          - type: 'null'
          title: External Sender Name
      type: object
      required:
      - thread_id
      - client_message_id
      - content_type
      - envelope
      title: InboundMessage
      description: 'Client -> server: post a new message.'
    IncidentCreateRequest:
      properties:
        severity:
          type: string
          maxLength: 40
          minLength: 1
          title: Severity
        title:
          type: string
          maxLength: 160
          minLength: 1
          title: Title
        description:
          type: string
          maxLength: 4000
          minLength: 1
          title: Description
        affected_components:
          items:
            type: string
          type: array
          title: Affected Components
      additionalProperties: false
      type: object
      required:
      - severity
      - title
      - description
      title: IncidentCreateRequest
    IncidentStatus:
      type: string
      enum:
      - open
      - mitigating
      - resolved
      title: IncidentStatus
    IncidentView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        status:
          $ref: '#/components/schemas/IncidentStatus'
        severity:
          type: string
          title: Severity
        title:
          type: string
          title: Title
        description:
          type: string
          title: Description
        affected_components:
          items:
            type: string
          type: array
          title: Affected Components
        resolved_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Resolved At
      type: object
      required:
      - id
      - status
      - severity
      - title
      - description
      - affected_components
      - resolved_at
      title: IncidentView
    InsightsResponse:
      properties:
        ai_payload:
          additionalProperties: true
          type: object
          title: Ai Payload
      type: object
      required:
      - ai_payload
      title: InsightsResponse
      description: The full ai_payload after on-demand insights finish.
    InviteListItem:
      properties:
        ref_token:
          type: string
          title: Ref Token
        invitee_phone_hash:
          type: string
          title: Invitee Phone Hash
        redeemed:
          type: boolean
          title: Redeemed
        invited_at:
          type: string
          format: date-time
          title: Invited At
        redeemed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Redeemed At
      type: object
      required:
      - ref_token
      - invitee_phone_hash
      - redeemed
      - invited_at
      - redeemed_at
      title: InviteListItem
    InviteListResponse:
      properties:
        invites:
          items:
            $ref: '#/components/schemas/InviteListItem'
          type: array
          title: Invites
        sent_count:
          type: integer
          title: Sent Count
        redeemed_count:
          type: integer
          title: Redeemed Count
      type: object
      required:
      - invites
      - sent_count
      - redeemed_count
      title: InviteListResponse
    InviteTrackRequest:
      properties:
        invitee_phone_hash:
          type: string
          maxLength: 64
          minLength: 64
          pattern: ^[0-9a-f]{64}$
          title: Invitee Phone Hash
      type: object
      required:
      - invitee_phone_hash
      title: InviteTrackRequest
      description: 'Body for POST /v1/invites/track.


        `invitee_phone_hash` is the UNSALTED SHA-256(e164) of the invited number,

        hex-encoded. Unsalted so the OTP-verify path can look it up later (the

        invitee''s salt is unknowable to us — it''s their own future random salt).'
    InviteTrackResponse:
      properties:
        ref_token:
          type: string
          title: Ref Token
        invite_url:
          type: string
          title: Invite Url
      type: object
      required:
      - ref_token
      - invite_url
      title: InviteTrackResponse
    JitDecideRequest:
      properties:
        resource_kind:
          $ref: '#/components/schemas/OperatorResourceKind'
        resource_id:
          type: string
          maxLength: 160
          minLength: 1
          title: Resource Id
        purpose:
          $ref: '#/components/schemas/OperatorPurpose'
        requested_duration_minutes:
          anyOf:
          - type: integer
            maximum: 480.0
            minimum: 5.0
          - type: 'null'
          title: Requested Duration Minutes
          default: 60
        justification:
          type: string
          maxLength: 600
          minLength: 4
          title: Justification
      additionalProperties: false
      type: object
      required:
      - resource_kind
      - resource_id
      - purpose
      - justification
      title: JitDecideRequest
    JitDecisionView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        resource_kind:
          $ref: '#/components/schemas/OperatorResourceKind'
        resource_id:
          type: string
          title: Resource Id
        purpose:
          $ref: '#/components/schemas/OperatorPurpose'
        outcome:
          type: string
          title: Outcome
        risk_score:
          anyOf:
          - type: integer
          - type: 'null'
          title: Risk Score
        reasons:
          items:
            type: string
          type: array
          title: Reasons
        audit_entry_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Audit Entry Id
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - resource_kind
      - resource_id
      - purpose
      - outcome
      - risk_score
      - reasons
      - audit_entry_id
      - created_at
      title: JitDecisionView
    JitGrantStatus:
      type: string
      enum:
      - active
      - expired
      - revoked
      - denied
      title: JitGrantStatus
    JitGrantView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        operator_user_id:
          type: string
          format: uuid
          title: Operator User Id
        resource_kind:
          $ref: '#/components/schemas/OperatorResourceKind'
        resource_id:
          type: string
          title: Resource Id
        purpose:
          $ref: '#/components/schemas/OperatorPurpose'
        scope:
          additionalProperties: true
          type: object
          title: Scope
        status:
          $ref: '#/components/schemas/JitGrantStatus'
        issued_at:
          type: string
          format: date-time
          title: Issued At
        expires_at:
          type: string
          format: date-time
          title: Expires At
        approved_by_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Approved By User Id
        audit_entry_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Audit Entry Id
        revoked_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Revoked At
        revocation_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Revocation Reason
      type: object
      required:
      - id
      - operator_user_id
      - resource_kind
      - resource_id
      - purpose
      - scope
      - status
      - issued_at
      - expires_at
      - approved_by_user_id
      - audit_entry_id
      - revoked_at
      - revocation_reason
      title: JitGrantView
    JitIssueRequest:
      properties:
        resource_kind:
          $ref: '#/components/schemas/OperatorResourceKind'
        resource_id:
          type: string
          maxLength: 160
          minLength: 1
          title: Resource Id
        purpose:
          $ref: '#/components/schemas/OperatorPurpose'
        requested_duration_minutes:
          anyOf:
          - type: integer
            maximum: 480.0
            minimum: 5.0
          - type: 'null'
          title: Requested Duration Minutes
          default: 60
        justification:
          type: string
          maxLength: 600
          minLength: 4
          title: Justification
        decision_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Decision Id
        approved_by_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Approved By User Id
        scope:
          additionalProperties: true
          type: object
          title: Scope
      additionalProperties: false
      type: object
      required:
      - resource_kind
      - resource_id
      - purpose
      - justification
      title: JitIssueRequest
    JitRevokeRequest:
      properties:
        reason:
          type: string
          maxLength: 280
          minLength: 3
          title: Reason
      additionalProperties: false
      type: object
      required:
      - reason
      title: JitRevokeRequest
    LiveTailEntry:
      properties:
        id:
          type: string
          title: Id
        kind:
          type: string
          title: Kind
        at:
          type: string
          format: date-time
          title: At
        detail:
          type: string
          title: Detail
      additionalProperties: false
      type: object
      required:
      - id
      - kind
      - at
      - detail
      title: LiveTailEntry
    LocationContextItem:
      properties:
        lat:
          type: number
          title: Lat
        lng:
          type: number
          title: Lng
        accuracy_m:
          type: number
          title: Accuracy M
        captured_at:
          type: string
          format: date-time
          title: Captured At
      type: object
      required:
      - lat
      - lng
      - accuracy_m
      - captured_at
      title: LocationContextItem
      description: Phase 8 — single Core Location fix.
    MarkReadRequest:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        up_to_message_id:
          type: string
          format: uuid
          title: Up To Message Id
      type: object
      required:
      - thread_id
      - up_to_message_id
      title: MarkReadRequest
    MatchEntry:
      properties:
        hash:
          type: string
          title: Hash
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        avatar_object_key:
          anyOf:
          - type: string
          - type: 'null'
          title: Avatar Object Key
      type: object
      required:
      - hash
      - user_id
      - display_name
      title: MatchEntry
    MatchRequest:
      properties:
        salt_b64:
          type: string
          maxLength: 64
          minLength: 22
          title: Salt B64
        hashes:
          items:
            type: string
          type: array
          maxItems: 5000
          title: Hashes
      type: object
      required:
      - salt_b64
      title: MatchRequest
      description: 'Body for POST /v1/contacts/match.


        `salt_b64` is the per-user contacts salt (32 random bytes, base64url, no

        padding). The client computes hashes locally as SHA-256(e164 || salt_bytes)

        and sends them along with the salt so the server can recompute matches

        against existing users.


        Why send the salt: lets us batch-match in O(N_users + N_hashes) without

        needing per-request crypto on the user table. The salt rotates monthly

        and is per-user, so no two users ever share salts — a server-side leak

        of one match request can''t be replayed against any other user''s contacts.'
    MatchResponse:
      properties:
        matches:
          items:
            $ref: '#/components/schemas/MatchEntry'
          type: array
          title: Matches
      type: object
      required:
      - matches
      title: MatchResponse
    MeResponse:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        email:
          anyOf:
          - type: string
          - type: 'null'
          title: Email
        phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Phone
        workspaces:
          items:
            $ref: '#/components/schemas/WorkspaceView'
          type: array
          title: Workspaces
        devices:
          items:
            $ref: '#/components/schemas/DeviceView'
          type: array
          title: Devices
        avatar_object_key:
          anyOf:
          - type: string
          - type: 'null'
          title: Avatar Object Key
        preferred_language:
          type: string
          title: Preferred Language
          default: en
        transcription_language_pref:
          anyOf:
          - type: string
          - type: 'null'
          title: Transcription Language Pref
        subscription_tier:
          type: string
          title: Subscription Tier
          default: free
        ai_training_consent_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Ai Training Consent At
        ai_processing_consent_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Ai Processing Consent At
        transport_e2e_acknowledged_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Transport E2E Acknowledged At
        workspace_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Workspace Id
        task_extraction_enabled:
          type: boolean
          title: Task Extraction Enabled
          default: true
        ai_feature_quotas:
          anyOf:
          - additionalProperties:
              $ref: '#/components/schemas/AIFeatureQuotaView'
            type: object
          - type: 'null'
          title: Ai Feature Quotas
      type: object
      required:
      - user_id
      - display_name
      - email
      - phone
      - workspaces
      - devices
      title: MeResponse
    MemoryItemCreate:
      properties:
        text:
          type: string
          title: Text
        kind:
          type: string
          title: Kind
          default: context
        person_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Person Id
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
      type: object
      required:
      - text
      title: MemoryItemCreate
    MemoryItemView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        person_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Person Id
        call_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Call Id
        text:
          type: string
          title: Text
        kind:
          type: string
          title: Kind
        occurred_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Occurred At
        created_at:
          type: string
          format: date-time
          title: Created At
        score:
          anyOf:
          - type: number
          - type: 'null'
          title: Score
      type: object
      required:
      - id
      - workspace_id
      - message_id
      - person_id
      - text
      - kind
      - occurred_at
      - created_at
      title: MemoryItemView
    MemoryItemsResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/MemoryItemView'
          type: array
          title: Items
      type: object
      required:
      - items
      title: MemoryItemsResponse
      description: 'All memory items across the caller''s workspaces, ordered most-recent

        first. iOS Memory tab uses this to group by topic / kind / person.'
    MemorySearchResponse:
      properties:
        query:
          type: string
          title: Query
        results:
          items:
            $ref: '#/components/schemas/MemoryItemView'
          type: array
          title: Results
      type: object
      required:
      - query
      - results
      title: MemorySearchResponse
    MessageAIDebug:
      properties:
        message_id:
          type: string
          format: uuid
          title: Message Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        content_type:
          type: string
          title: Content Type
        status:
          anyOf:
          - type: string
          - type: 'null'
          title: Status
        has_ai_payload:
          type: boolean
          title: Has Ai Payload
        pa_kind:
          anyOf:
          - type: string
          - type: 'null'
          title: Pa Kind
        pa_title:
          anyOf:
          - type: string
          - type: 'null'
          title: Pa Title
        task_count:
          type: integer
          title: Task Count
        urgency:
          anyOf:
          - type: string
          - type: 'null'
          title: Urgency
        created_at:
          type: string
          format: date-time
          title: Created At
        summary_short:
          anyOf:
          - type: string
          - type: 'null'
          title: Summary Short
        intent_summary:
          anyOf:
          - type: string
          - type: 'null'
          title: Intent Summary
        open_questions_count:
          type: integer
          title: Open Questions Count
        is_self_thread:
          type: boolean
          title: Is Self Thread
      type: object
      required:
      - message_id
      - thread_id
      - content_type
      - status
      - has_ai_payload
      - pa_kind
      - pa_title
      - task_count
      - urgency
      - created_at
      - summary_short
      - intent_summary
      - open_questions_count
      - is_self_thread
      title: MessageAIDebug
    MessageInfoView:
      properties:
        message_id:
          type: string
          format: uuid
          title: Message Id
        server_received_at:
          type: string
          format: date-time
          title: Server Received At
        edited_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Edited At
        deleted_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Deleted At
        total_recipient_devices:
          type: integer
          title: Total Recipient Devices
        delivered_to_devices:
          type: integer
          title: Delivered To Devices
        read_by_devices:
          type: integer
          title: Read By Devices
        deliveries:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Deliveries
      type: object
      required:
      - message_id
      - server_received_at
      - edited_at
      - deleted_at
      - total_recipient_devices
      - delivered_to_devices
      - read_by_devices
      - deliveries
      title: MessageInfoView
      description: 'Phase 9 — per-message delivery + read aggregation.


        The recipient breakdown is computed on the fly from the

        ``message_recipients`` rows the WS / list paths already maintain.

        Returned to the iOS message-info screen so the sender can see

        "delivered to 3 of 4 devices, read by 2".'
    MessageReconciliationView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        content_type:
          type: string
          title: Content Type
        status:
          type: string
          title: Status
        ai_payload:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Ai Payload
        updated_at:
          type: string
          format: date-time
          title: Updated At
        processing_deadline:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Processing Deadline
        failure_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Failure Reason
      type: object
      required:
      - id
      - thread_id
      - content_type
      - status
      - ai_payload
      - updated_at
      title: MessageReconciliationView
      description: "Shape returned by GET /v1/messages/{id} for reconciliation.\n\nMinimal by design —\
        \ clients use this ONLY to merge fresh\n``status`` / ``ai_payload`` into an already-decrypted\
        \ local\nbubble. The ciphertext / envelope columns aren't included; the\nclient already has those\
        \ from the original delivery payload.\n\n2026-05-14 additions for the lease state machine:\n \
        \ * ``processing_deadline`` — when the current processing lease\n    expires (None if the row\
        \ isn't currently being processed).\n    Clients use this to stop reconciling after the deadline\
        \ so a\n    stalled server-side pipeline doesn't generate forever-polling\n    on the device.\n\
        \  * ``failure_reason`` — populated only when ``status='failed'``;\n    stable short code (``lease_exhausted``,\
        \ ``stage_failed``, …)\n    the client renders in the bubble's \"what went wrong?\" sheet."
    MessageSearchHit:
      properties:
        message_id:
          type: string
          format: uuid
          title: Message Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        snippet:
          type: string
          title: Snippet
        rank:
          type: number
          title: Rank
        server_received_at:
          type: string
          format: date-time
          title: Server Received At
      type: object
      required:
      - message_id
      - thread_id
      - snippet
      - rank
      - server_received_at
      title: MessageSearchHit
      description: 'One result from server-side AI-summary search.


        The server only sees the AI summary (TIER 1 workspaces) — never

        the encrypted plaintext on Tier 2/3. Search hits therefore carry

        the summary excerpt, not the raw message body. The iOS / Android

        client surfaces the excerpt + lets the user tap through to the

        decrypted bubble.'
    MessageTransitionEntry:
      properties:
        from_status:
          anyOf:
          - type: string
          - type: 'null'
          title: From Status
        to_status:
          type: string
          title: To Status
        actor:
          type: string
          title: Actor
        reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Reason
        attempts:
          type: integer
          title: Attempts
        at:
          type: string
          format: date-time
          title: At
      additionalProperties: false
      type: object
      required:
      - from_status
      - to_status
      - actor
      - reason
      - attempts
      - at
      title: MessageTransitionEntry
      description: One row from ``message_state_transitions`` for a single message.
    MessageTransitionHistory:
      properties:
        message_id:
          type: string
          title: Message Id
        current_status:
          type: string
          title: Current Status
        current_failure_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Current Failure Reason
        current_processing_attempts:
          type: integer
          title: Current Processing Attempts
        current_processing_owner:
          anyOf:
          - type: string
          - type: 'null'
          title: Current Processing Owner
        current_processing_lease_expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Current Processing Lease Expires At
        transitions:
          items:
            $ref: '#/components/schemas/MessageTransitionEntry'
          type: array
          title: Transitions
      additionalProperties: false
      type: object
      required:
      - message_id
      - current_status
      - current_failure_reason
      - current_processing_attempts
      - current_processing_owner
      - current_processing_lease_expires_at
      - transitions
      title: MessageTransitionHistory
      description: Full status-transition timeline for one message.
    MessagesDebugResponse:
      properties:
        total_in_threads:
          type: integer
          title: Total In Threads
        rows:
          items:
            $ref: '#/components/schemas/MessageAIDebug'
          type: array
          title: Rows
      type: object
      required:
      - total_in_threads
      - rows
      title: MessagesDebugResponse
    ModelPin:
      properties:
        model_id:
          type: string
          title: Model Id
        version:
          anyOf:
          - type: string
          - type: 'null'
          title: Version
      additionalProperties: false
      type: object
      required:
      - model_id
      title: ModelPin
    MuteRequest:
      properties:
        duration_hours:
          anyOf:
          - type: number
          - type: 'null'
          title: Duration Hours
      type: object
      title: MuteRequest
      description: 'Mute a thread for `duration_hours` (or unmute when omitted/0).


        Common values: 1 (an hour), 8 (a workday), 168 (a week), 720 (a month).

        NULL/0 unmutes by clearing the timestamp. We don''t expose "mute forever"

        in v0 — it leads to forgotten-thread debt; users can always re-mute.'
    MuteResponse:
      properties:
        muted_until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Muted Until
      type: object
      required:
      - muted_until
      title: MuteResponse
    NarrateRequest:
      properties:
        text:
          type: string
          maxLength: 4000
          minLength: 1
          title: Text
        voice_id:
          anyOf:
          - type: string
            maxLength: 128
          - type: 'null'
          title: Voice Id
      type: object
      required:
      - text
      title: NarrateRequest
    NetworkMetricsResponse:
      properties:
        users_total:
          type: integer
          title: Users Total
        active_devices_24h:
          type: integer
          title: Active Devices 24H
        messages_24h:
          type: integer
          title: Messages 24H
        calls_24h:
          type: integer
          title: Calls 24H
        push_success_rate_24h:
          type: number
          title: Push Success Rate 24H
        registered_tenants:
          type: integer
          title: Registered Tenants
        as_of:
          type: string
          format: date-time
          title: As Of
      additionalProperties: false
      type: object
      required:
      - users_total
      - active_devices_24h
      - messages_24h
      - calls_24h
      - push_success_rate_24h
      - registered_tenants
      - as_of
      title: NetworkMetricsResponse
    NotificationPrefsInput:
      properties:
        privacy_mode:
          type: string
          enum:
          - full
          - sender
          - hide_content
          - hide_all
          title: Privacy Mode
        global_muted_until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Global Muted Until
      type: object
      required:
      - privacy_mode
      title: NotificationPrefsInput
    NotificationPrefsOutput:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        privacy_mode:
          type: string
          title: Privacy Mode
        global_muted_until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Global Muted Until
      type: object
      required:
      - user_id
      - privacy_mode
      - global_muted_until
      title: NotificationPrefsOutput
    OpenQuestionItem:
      properties:
        question:
          type: string
          title: Question
        message_id:
          type: string
          format: uuid
          title: Message Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        thread_title:
          anyOf:
          - type: string
          - type: 'null'
          title: Thread Title
        sender_display_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Sender Display Name
        asked_at:
          type: string
          format: date-time
          title: Asked At
      type: object
      required:
      - question
      - message_id
      - thread_id
      - thread_title
      - sender_display_name
      - asked_at
      title: OpenQuestionItem
      description: 'A single question waiting on the caller, with full source

        attribution so the iOS client can render it as a NavigationLink

        that deep-links into the thread + scrolls to the source message.'
    OperatorInboxResponse:
      properties:
        as_of:
          type: string
          format: date-time
          title: As Of
        cases:
          items:
            $ref: '#/components/schemas/CaseView'
          type: array
          title: Cases
        degraded:
          type: boolean
          title: Degraded
          default: false
        degraded_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Degraded Reason
      type: object
      required:
      - as_of
      - cases
      title: OperatorInboxResponse
    OperatorMessageSendRequest:
      properties:
        case_id:
          type: string
          format: uuid
          title: Case Id
        message:
          $ref: '#/components/schemas/InboundMessage'
      additionalProperties: false
      type: object
      required:
      - case_id
      - message
      title: OperatorMessageSendRequest
    OperatorPurpose:
      type: string
      enum:
      - service_request
      - complaint_handling
      - audit
      - legal_hold
      - quality_review
      - incident_response
      - fraud_investigation
      - aml_review
      - relationship_management
      title: OperatorPurpose
    OperatorResourceKind:
      type: string
      enum:
      - conversation
      - case
      - customer
      - audit_export
      - tenant_config
      - incident
      - bank_context
      title: OperatorResourceKind
    OperatorRole:
      type: string
      enum:
      - business_operator_admin
      - application_admin
      - backend_admin
      - relationship_manager
      - complaints_handler
      - fraud_disputes_handler
      - supervisor
      - compliance_supervisor
      - auditor
      - support_lead
      title: OperatorRole
    OperatorSessionResponse:
      properties:
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        user_id:
          type: string
          format: uuid
          title: User Id
        roles:
          items:
            $ref: '#/components/schemas/OperatorRole'
          type: array
          title: Roles
        profile_status:
          type: string
          title: Profile Status
        active_grants:
          items:
            $ref: '#/components/schemas/JitGrantView'
          type: array
          title: Active Grants
      type: object
      required:
      - workspace_id
      - user_id
      - roles
      - profile_status
      - active_grants
      title: OperatorSessionResponse
    OpsDashboardResponse:
      properties:
        as_of:
          type: string
          format: date-time
          title: As Of
        window:
          $ref: '#/components/schemas/WindowMeta'
        command_bar:
          $ref: '#/components/schemas/CommandBar'
        business:
          $ref: '#/components/schemas/BusinessSnapshot'
        service_health:
          items:
            $ref: '#/components/schemas/ServiceTile'
          type: array
          title: Service Health
        ai_pipeline:
          $ref: '#/components/schemas/AIPipelineSnapshot'
        call_quality:
          $ref: '#/components/schemas/CallQualitySnapshot'
        alerts:
          items:
            $ref: '#/components/schemas/AlertEntry'
          type: array
          title: Alerts
        live_tail:
          items:
            $ref: '#/components/schemas/LiveTailEntry'
          type: array
          title: Live Tail
      additionalProperties: false
      type: object
      required:
      - as_of
      - window
      - command_bar
      - business
      - service_health
      - ai_pipeline
      - call_quality
      - alerts
      - live_tail
      title: OpsDashboardResponse
    OutboundDelivery:
      properties:
        type:
          type: string
          title: Type
          default: message.new
        message_id:
          type: string
          format: uuid
          title: Message Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        sender_device_id:
          type: string
          format: uuid
          title: Sender Device Id
        sender_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Sender User Id
        sender_display_name:
          type: string
          title: Sender Display Name
          default: ''
        content_type:
          type: string
          title: Content Type
        sender_eph_public:
          type: string
          title: Sender Eph Public
        aad:
          type: string
          title: Aad
        ciphertext:
          type: string
          title: Ciphertext
        nonce:
          type: string
          title: Nonce
        signature:
          type: string
          title: Signature
        wrapped_key:
          type: string
          title: Wrapped Key
        server_received_at:
          type: string
          format: date-time
          title: Server Received At
        media_object_key:
          anyOf:
          - type: string
          - type: 'null'
          title: Media Object Key
        total_recipient_devices:
          type: integer
          title: Total Recipient Devices
          default: 0
        delivered_to_devices:
          type: integer
          title: Delivered To Devices
          default: 0
        read_by_devices:
          type: integer
          title: Read By Devices
          default: 0
        ai_payload:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Ai Payload
        status:
          type: string
          title: Status
          default: delivered
        reply_to_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Reply To Message Id
        forwarded_from_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Forwarded From Message Id
        supersedes_message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Supersedes Message Id
        reactions:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Reactions
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
        external_sender_name:
          anyOf:
          - type: string
          - type: 'null'
          title: External Sender Name
      type: object
      required:
      - message_id
      - thread_id
      - workspace_id
      - sender_device_id
      - sender_user_id
      - content_type
      - sender_eph_public
      - aad
      - ciphertext
      - nonce
      - signature
      - wrapped_key
      - server_received_at
      title: OutboundDelivery
      description: 'Server -> recipient device over WebSocket: a freshly-arrived message.


        The recipient sees the encrypted envelope; the wrapped_key is only the one

        encrypted to *this* device''s public key.'
    OverrideBody:
      properties:
        bypass_all:
          type: boolean
          title: Bypass All
          description: Skip ALL gates for this user. Equivalent to ``is_internal=true`` but with optional
            expiry. Use for time-bounded grants ('free month for VIP'); use ``is_internal`` for permanent
            employee/tester status.
          default: false
        feature_caps:
          additionalProperties:
            $ref: '#/components/schemas/FeatureCapSpec'
          type: object
          title: Feature Caps
          description: Per-feature override slices. Keys are FEATURE_* from spend_meter (voice_note, ask,
            thread_assistant, insights_rerun, brief). Missing features fall through to DEFAULT_BUDGETS.
        dollar_cap_micros:
          anyOf:
          - type: integer
            maximum: 1000000000.0
            minimum: 0.0
          - type: 'null'
          title: Dollar Cap Micros
          description: Override the $0.10/month silent backstop, in micros. Set to a very high number
            (e.g. 1_000_000_000 = $1000) to effectively disable the backstop.
        is_internal:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Is Internal
          description: When non-None, also update ``users.is_internal``. Use ``true`` for permanent tester/employee
            bypass; ``false`` to clear a prior internal flag. Leave ``null`` to only edit the JSONB override.
        expires_in_days:
          anyOf:
          - type: integer
            maximum: 365.0
            minimum: 1.0
          - type: 'null'
          title: Expires In Days
          description: Set the override to auto-expire N days from now. Mutually exclusive with ``expires_at``.
            Leave both null for permanent grants.
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
          description: Explicit expiry timestamp. Mutually exclusive with ``expires_in_days``.
        reason:
          type: string
          maxLength: 240
          minLength: 3
          title: Reason
          description: Required free-text justification. Goes into the audit row + ``ai_quota_override._reason``.
            Future-you (or your auditor) will appreciate it.
      additionalProperties: false
      type: object
      required:
      - reason
      title: OverrideBody
      description: 'POST body. Mirrors ``users.ai_quota_override`` JSONB shape, with

        typed validation on each knob.'
    OverrideResponse:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        is_internal:
          type: boolean
          title: Is Internal
        override:
          additionalProperties: true
          type: object
          title: Override
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
        effective_caps:
          additionalProperties:
            $ref: '#/components/schemas/EffectiveCap'
          type: object
          title: Effective Caps
      additionalProperties: false
      type: object
      required:
      - user_id
      - is_internal
      - override
      - expires_at
      - effective_caps
      title: OverrideResponse
    PatchCorrectionsRequest:
      properties:
        corrections:
          additionalProperties: true
          type: object
          title: Corrections
      type: object
      required:
      - corrections
      title: PatchCorrectionsRequest
      description: 'User-supplied overrides. The derivation worker NEVER writes to

        `user_corrections` (see derivation.py audit fix); this is the

        sole writer. Shape mirrors the identity dict so corrections can

        target any derived field (display_name override, do_not_repeat_

        corrections list, etc.).'
    PeerDeviceView:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        label:
          type: string
          title: Label
        platform:
          type: string
          title: Platform
        identity_public_key_b64:
          type: string
          title: Identity Public Key B64
        encryption_public_key_b64:
          type: string
          title: Encryption Public Key B64
        voice_identity_pub_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: Voice Identity Pub B64
        is_active:
          type: boolean
          title: Is Active
          default: true
        device_cert_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: Device Cert B64
      type: object
      required:
      - device_id
      - label
      - platform
      - identity_public_key_b64
      - encryption_public_key_b64
      title: PeerDeviceView
    PeerDevicesResponse:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        devices:
          items:
            $ref: '#/components/schemas/PeerDeviceView'
          type: array
          title: Devices
        user_identity_public_key_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: User Identity Public Key B64
      type: object
      required:
      - user_id
      - display_name
      - devices
      title: PeerDevicesResponse
    PendingConfirmationResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Items
      type: object
      required:
      - items
      title: PendingConfirmationResponse
    PeopleListResponse:
      properties:
        people:
          items:
            $ref: '#/components/schemas/PersonView'
          type: array
          title: People
      type: object
      required:
      - people
      title: PeopleListResponse
    PersonCallMention:
      properties:
        call_id:
          type: string
          format: uuid
          title: Call Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        first_mention_at:
          type: string
          format: date-time
          title: First Mention At
        last_mention_at:
          type: string
          format: date-time
          title: Last Mention At
        mention_count:
          type: integer
          title: Mention Count
        sample_text:
          type: string
          title: Sample Text
      type: object
      required:
      - call_id
      - thread_id
      - first_mention_at
      - last_mention_at
      - mention_count
      - sample_text
      title: PersonCallMention
      description: 'One row in the per-person, per-call mention rollup. Each call

        that mentioned the person collapses to a single row regardless of

        how many distinct memory rows reference it.'
    PersonCallMentionsResponse:
      properties:
        person_id:
          type: string
          format: uuid
          title: Person Id
        mentions:
          items:
            $ref: '#/components/schemas/PersonCallMention'
          type: array
          title: Mentions
      type: object
      required:
      - person_id
      - mentions
      title: PersonCallMentionsResponse
    PersonDetailResponse:
      properties:
        person:
          $ref: '#/components/schemas/PersonView'
        memories:
          items:
            $ref: '#/components/schemas/MemoryItemView'
          type: array
          title: Memories
        recent_message_ids:
          items:
            type: string
            format: uuid
          type: array
          title: Recent Message Ids
      type: object
      required:
      - person
      - memories
      - recent_message_ids
      title: PersonDetailResponse
    PersonView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        canonical_name:
          type: string
          title: Canonical Name
        aliases:
          items:
            type: string
          type: array
          title: Aliases
        phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Phone
        email:
          anyOf:
          - type: string
          - type: 'null'
          title: Email
        role:
          anyOf:
          - type: string
          - type: 'null'
          title: Role
        company:
          anyOf:
          - type: string
          - type: 'null'
          title: Company
        last_seen_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Seen At
        mention_count:
          type: integer
          title: Mention Count
        user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: User Id
      type: object
      required:
      - id
      - workspace_id
      - canonical_name
      - aliases
      - phone
      - email
      - role
      - company
      - last_seen_at
      - mention_count
      - user_id
      title: PersonView
    PhoneStartInput:
      properties:
        phone:
          type: string
          title: Phone
          description: E.164 phone number, e.g. +14155551234
        display_name:
          anyOf:
          - type: string
            maxLength: 120
          - type: 'null'
          title: Display Name
          description: Suggested display name; only persisted if this is a new user.
        channel:
          type: string
          enum:
          - sms
          - call
          title: Channel
          default: sms
      type: object
      required:
      - phone
      title: PhoneStartInput
    PhoneStartOutput:
      properties:
        sent:
          type: boolean
          title: Sent
        expires_at:
          type: string
          format: date-time
          title: Expires At
        dev_code:
          anyOf:
          - type: string
          - type: 'null'
          title: Dev Code
      type: object
      required:
      - sent
      - expires_at
      title: PhoneStartOutput
    PhoneVerifyInput:
      properties:
        phone:
          type: string
          title: Phone
        code:
          type: string
          maxLength: 6
          minLength: 6
          title: Code
        device_label:
          type: string
          maxLength: 120
          title: Device Label
        device_platform:
          type: string
          maxLength: 32
          title: Device Platform
          default: ios
        identity_public_key_b64:
          type: string
          maxLength: 128
          minLength: 1
          title: Identity Public Key B64
        encryption_public_key_b64:
          type: string
          maxLength: 128
          minLength: 1
          title: Encryption Public Key B64
        signed_prekey_signature_b64:
          type: string
          maxLength: 128
          minLength: 1
          title: Signed Prekey Signature B64
        voice_identity_pub_b64:
          anyOf:
          - type: string
            maxLength: 128
          - type: 'null'
          title: Voice Identity Pub B64
        user_identity_public_key_b64:
          anyOf:
          - type: string
            maxLength: 128
          - type: 'null'
          title: User Identity Public Key B64
        device_cert_b64:
          anyOf:
          - type: string
            maxLength: 128
          - type: 'null'
          title: Device Cert B64
        wavelink_noise_pub_b64:
          anyOf:
          - type: string
            maxLength: 128
          - type: 'null'
          title: Wavelink Noise Pub B64
      type: object
      required:
      - phone
      - code
      - device_label
      - identity_public_key_b64
      - encryption_public_key_b64
      - signed_prekey_signature_b64
      title: PhoneVerifyInput
      description: 'Atomic phone-OTP bootstrap. The client doesn''t have a device_id

        yet — it has device public keys (just generated locally). We verify

        the OTP, find-or-create the User, register the device, bind tokens —

        all in one call. Solves the chicken-and-egg of pre-registered devices.'
    PhoneVerifyOutput:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        device_id:
          type: string
          format: uuid
          title: Device Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        is_new_user:
          type: boolean
          title: Is New User
        display_name:
          type: string
          title: Display Name
        access_token:
          type: string
          title: Access Token
        refresh_token:
          type: string
          title: Refresh Token
        access_expires_at:
          type: string
          format: date-time
          title: Access Expires At
        refresh_expires_at:
          type: string
          format: date-time
          title: Refresh Expires At
      type: object
      required:
      - user_id
      - device_id
      - workspace_id
      - is_new_user
      - display_name
      - access_token
      - refresh_token
      - access_expires_at
      - refresh_expires_at
      title: PhoneVerifyOutput
    PinnedThreadView:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        pinned_at:
          type: string
          format: date-time
          title: Pinned At
      type: object
      required:
      - thread_id
      - pinned_at
      title: PinnedThreadView
    PlatformAuditEntry:
      properties:
        seq:
          type: integer
          title: Seq
        at:
          type: string
          format: date-time
          title: At
        actor:
          type: string
          title: Actor
        action:
          type: string
          title: Action
        payload:
          additionalProperties: true
          type: object
          title: Payload
      additionalProperties: false
      type: object
      required:
      - seq
      - at
      - actor
      - action
      - payload
      title: PlatformAuditEntry
    PlatformAuditResponse:
      properties:
        entries:
          items:
            $ref: '#/components/schemas/PlatformAuditEntry'
          type: array
          title: Entries
        total:
          type: integer
          title: Total
        note:
          anyOf:
          - type: string
          - type: 'null'
          title: Note
      additionalProperties: false
      type: object
      required:
      - entries
      - total
      - note
      title: PlatformAuditResponse
    PolicyOut:
      properties:
        policy:
          $ref: '#/components/schemas/AiPolicy'
        updated_by_actor:
          anyOf:
          - type: string
          - type: 'null'
          title: Updated By Actor
        updated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Updated At
      additionalProperties: false
      type: object
      required:
      - policy
      - updated_by_actor
      - updated_at
      title: PolicyOut
    PolicySetRequest:
      properties:
        policy:
          $ref: '#/components/schemas/AiPolicy'
      additionalProperties: false
      type: object
      required:
      - policy
      title: PolicySetRequest
    PolicySetResponse:
      properties:
        policy:
          $ref: '#/components/schemas/AiPolicy'
        updated_by_actor:
          type: string
          title: Updated By Actor
        updated_at:
          type: string
          format: date-time
          title: Updated At
      additionalProperties: false
      type: object
      required:
      - policy
      - updated_by_actor
      - updated_at
      title: PolicySetResponse
    PreCallContextView:
      properties:
        call_id:
          type: string
          format: uuid
          title: Call Id
        last_messages:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Last Messages
        last_call_summary:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Call Summary
        open_questions:
          items:
            type: string
          type: array
          title: Open Questions
        relevant_memories:
          items:
            type: string
          type: array
          title: Relevant Memories
        talking_points:
          items:
            type: string
          type: array
          title: Talking Points
      type: object
      required:
      - call_id
      - last_messages
      - last_call_summary
      - open_questions
      - relevant_memories
      - talking_points
      title: PreCallContextView
      description: "Aggregated context shown during the 3-8s ring window (#5).\n\nPulls the data iOS wants\
        \ for a \"before-call brief\" card:\n\n  * ``last_messages`` — the last 3 messages in the call's\
        \ thread,\n    most recent first. Server-stored summaries (``ai_payload.\n    summary_short``)\
        \ are sent in-band; the bodies stay encrypted.\n  * ``last_call_summary`` — the prior call's ``summary_short``\
        \ if\n    this thread had one in the last 30 days.\n  * ``open_questions`` — non-resolved open\
        \ questions from the\n    thread's recent ai_payloads.\n  * ``relevant_memories`` — top-K semantic\
        \ memories from the\n    workspace memory store, queried with the most-recent message\n    text\
        \ as the search anchor (no extra LLM call).\n  * ``talking_points`` — distilled to 1-3 lines the\
        \ user can\n    actually act on. Deterministic post-processing of the above."
    PromisesResponse:
      properties:
        made:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Made
        received:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Received
        kept:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Kept
      type: object
      required:
      - made
      - received
      - kept
      title: PromisesResponse
      description: 'Promise tracking — three buckets the iOS Work tab renders as a section.


        `made` and `received` are open promises (status=open). `kept` is a recent

        history of promises the caller has completed in the last 30 days, used

        to show a "promises kept" stats line ("12 promises kept this month").'
    ReactionView:
      properties:
        emoji:
          type: string
          title: Emoji
        user_id:
          type: string
          format: uuid
          title: User Id
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - emoji
      - user_id
      - created_at
      title: ReactionView
    ReactionsResponse:
      properties:
        message_id:
          type: string
          format: uuid
          title: Message Id
        reactions:
          items:
            $ref: '#/components/schemas/ReactionView'
          type: array
          title: Reactions
      type: object
      required:
      - message_id
      - reactions
      title: ReactionsResponse
    RefreshInput:
      properties:
        refresh_token:
          type: string
          title: Refresh Token
      type: object
      required:
      - refresh_token
      title: RefreshInput
    RefreshOutput:
      properties:
        access_token:
          type: string
          title: Access Token
        refresh_token:
          type: string
          title: Refresh Token
        access_expires_at:
          type: string
          format: date-time
          title: Access Expires At
        refresh_expires_at:
          type: string
          format: date-time
          title: Refresh Expires At
      type: object
      required:
      - access_token
      - refresh_token
      - access_expires_at
      - refresh_expires_at
      title: RefreshOutput
    RegisterDeviceInput:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        label:
          type: string
          maxLength: 120
          minLength: 1
          title: Label
        platform:
          type: string
          pattern: ^(ios|ipados|macos|android|web|ai-processor)$
          title: Platform
        identity_public_key_b64:
          type: string
          title: Identity Public Key B64
        encryption_public_key_b64:
          type: string
          title: Encryption Public Key B64
        signed_prekey_signature_b64:
          type: string
          title: Signed Prekey Signature B64
        push_token:
          anyOf:
          - type: string
          - type: 'null'
          title: Push Token
        voice_identity_pub_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: Voice Identity Pub B64
        device_cert_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: Device Cert B64
        wavelink_noise_pub_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: Wavelink Noise Pub B64
      type: object
      required:
      - user_id
      - label
      - platform
      - identity_public_key_b64
      - encryption_public_key_b64
      - signed_prekey_signature_b64
      title: RegisterDeviceInput
    RegisterDeviceOutput:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
      type: object
      required:
      - device_id
      title: RegisterDeviceOutput
    ReminderContextItem:
      properties:
        title:
          type: string
          maxLength: 300
          title: Title
        list_name:
          anyOf:
          - type: string
            maxLength: 120
          - type: 'null'
          title: List Name
        due:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Due
        is_completed:
          type: boolean
          title: Is Completed
          default: false
        priority:
          type: integer
          title: Priority
          default: 0
        notes:
          anyOf:
          - type: string
            maxLength: 2000
          - type: 'null'
          title: Notes
      type: object
      required:
      - title
      title: ReminderContextItem
      description: 'One iOS Reminders.app item from the client-supplied bundle.


        Phase 7b — same shape as the calendar bundle but for EKReminder

        entities. Read by the `list_reminders` tool.'
    ReportRequest:
      properties:
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        reported_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Reported User Id
        reason:
          type: string
          pattern: ^(spam|harassment|hate_speech|sexual_content|violence|self_harm|illegal|other)$
          title: Reason
        details:
          anyOf:
          - type: string
            maxLength: 2000
          - type: 'null'
          title: Details
      type: object
      required:
      - reason
      title: ReportRequest
      description: 'Body for POST /v1/moderation/report.


        `message_id` is optional — users can also report a *user* without

        citing a specific message (e.g. an account-level report). When omitted,

        we still record `reported_user_id` so a moderator can see the trail.'
    ReportResponse:
      properties:
        report_id:
          type: string
          format: uuid
          title: Report Id
        status:
          type: string
          title: Status
        submitted_at:
          type: string
          format: date-time
          title: Submitted At
        review_window_hours:
          type: integer
          title: Review Window Hours
          default: 24
      type: object
      required:
      - report_id
      - status
      - submitted_at
      title: ReportResponse
    RequestMagicLinkRequest:
      properties:
        email:
          type: string
          format: email
          title: Email
          description: Email to authenticate as
      additionalProperties: false
      type: object
      required:
      - email
      title: RequestMagicLinkRequest
    RequestMagicLinkResponse:
      properties:
        sent:
          type: boolean
          title: Sent
          default: true
        message:
          type: string
          title: Message
          default: If your email is allowed, you'll receive a magic link shortly.
        dev_magic_token:
          anyOf:
          - type: string
          - type: 'null'
          title: Dev Magic Token
      additionalProperties: false
      type: object
      title: RequestMagicLinkResponse
      description: 'Generic response — does NOT reveal whether the email is in the

        allowlist (no oracle for "is X an admin"). The dev-mode field

        ``dev_magic_token`` is populated only in non-prod so testing

        end-to-end doesn''t require an SMTP backend; it''s None in prod.'
    RevokeDeviceResponse:
      properties:
        revoked_device_id:
          type: string
          format: uuid
          title: Revoked Device Id
      type: object
      required:
      - revoked_device_id
      title: RevokeDeviceResponse
    RunListResponse:
      properties:
        runs:
          items:
            $ref: '#/components/schemas/RunOut'
          type: array
          title: Runs
        total_count:
          type: integer
          title: Total Count
        repo_slug:
          type: string
          title: Repo Slug
      additionalProperties: false
      type: object
      required:
      - runs
      - total_count
      - repo_slug
      title: RunListResponse
    RunOut:
      properties:
        id:
          type: integer
          title: Id
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
        workflow_id:
          type: integer
          title: Workflow Id
        head_branch:
          anyOf:
          - type: string
          - type: 'null'
          title: Head Branch
        head_sha:
          type: string
          title: Head Sha
        event:
          type: string
          title: Event
        status:
          type: string
          title: Status
        conclusion:
          anyOf:
          - type: string
          - type: 'null'
          title: Conclusion
        actor_login:
          anyOf:
          - type: string
          - type: 'null'
          title: Actor Login
        run_number:
          type: integer
          title: Run Number
        run_attempt:
          type: integer
          title: Run Attempt
        html_url:
          type: string
          title: Html Url
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
        run_started_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Run Started At
      additionalProperties: false
      type: object
      required:
      - id
      - name
      - workflow_id
      - head_branch
      - head_sha
      - event
      - status
      - conclusion
      - actor_login
      - run_number
      - run_attempt
      - html_url
      - created_at
      - updated_at
      - run_started_at
      title: RunOut
    RuntimeConfigResponse:
      properties:
        version:
          type: integer
          title: Version
          default: 1
        features:
          additionalProperties:
            type: boolean
          type: object
          title: Features
        copy:
          additionalProperties:
            type: string
          type: object
          title: Copy
        banners:
          items:
            $ref: '#/components/schemas/BannerView'
          type: array
          title: Banners
        modules:
          items:
            $ref: '#/components/schemas/RuntimeModuleView'
          type: array
          title: Modules
      type: object
      required:
      - features
      - copy
      - banners
      title: RuntimeConfigResponse
    RuntimeFlagRequest:
      properties:
        name:
          type: string
          maxLength: 64
          minLength: 1
          title: Name
        enabled:
          type: boolean
          title: Enabled
        reason:
          type: string
          maxLength: 280
          minLength: 3
          title: Reason
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
        rollout_percentage:
          anyOf:
          - type: integer
            maximum: 100.0
            minimum: 0.0
          - type: 'null'
          title: Rollout Percentage
      additionalProperties: false
      type: object
      required:
      - name
      - enabled
      - reason
      title: RuntimeFlagRequest
    RuntimeFlagResponse:
      properties:
        name:
          type: string
          title: Name
        enabled:
          type: boolean
          title: Enabled
        audit_entry_id:
          type: string
          format: uuid
          title: Audit Entry Id
      type: object
      required:
      - name
      - enabled
      - audit_entry_id
      title: RuntimeFlagResponse
    RuntimeModuleView:
      properties:
        key:
          type: string
          title: Key
        display_name:
          type: string
          title: Display Name
        feature_flag:
          type: string
          title: Feature Flag
        release_state:
          type: string
          enum:
          - dark
          - internal
          - private_beta
          - enterprise_pilot
          - production
          title: Release State
        default_enabled:
          type: boolean
          title: Default Enabled
        kill_switch:
          type: string
          title: Kill Switch
        client_capability_mode:
          anyOf:
          - type: string
          - type: 'null'
          title: Client Capability Mode
        surfaces:
          items:
            type: string
          type: array
          title: Surfaces
        dependencies:
          items:
            type: string
          type: array
          title: Dependencies
        controls:
          items:
            type: string
          type: array
          title: Controls
        health:
          type: string
          title: Health
        evidence_doc:
          type: string
          title: Evidence Doc
      type: object
      required:
      - key
      - display_name
      - feature_flag
      - release_state
      - default_enabled
      - kill_switch
      - surfaces
      - dependencies
      - controls
      - health
      - evidence_doc
      title: RuntimeModuleView
    SecuritySnapshot:
      properties:
        as_of:
          type: string
          format: date-time
          title: As Of
        window:
          type: string
          title: Window
        otp_requests_window:
          type: integer
          title: Otp Requests Window
        otp_verified_window:
          type: integer
          title: Otp Verified Window
        otp_verify_rate:
          type: number
          title: Otp Verify Rate
        otp_high_attempts:
          type: integer
          title: Otp High Attempts
        token_families_active:
          type: integer
          title: Token Families Active
        token_reuse_detected_window:
          type: integer
          title: Token Reuse Detected Window
        devices_revoked_window:
          type: integer
          title: Devices Revoked Window
      type: object
      required:
      - as_of
      - window
      - otp_requests_window
      - otp_verified_window
      - otp_verify_rate
      - otp_high_attempts
      - token_families_active
      - token_reuse_detected_window
      - devices_revoked_window
      title: SecuritySnapshot
    SegmentBeginInput:
      properties:
        started_at_ms:
          type: integer
          minimum: 0.0
          title: Started At Ms
        duration_ms:
          type: integer
          maximum: 60000.0
          minimum: 1.0
          title: Duration Ms
        wrapped_key_b64:
          type: string
          title: Wrapped Key B64
        nonce_b64:
          type: string
          title: Nonce B64
        aad_b64:
          type: string
          title: Aad B64
        sender_eph_public_b64:
          type: string
          title: Sender Eph Public B64
        signature_b64:
          type: string
          title: Signature B64
        envelope_version:
          type: integer
          title: Envelope Version
          default: 1
        content_length:
          type: integer
          exclusiveMinimum: 0.0
          title: Content Length
      type: object
      required:
      - started_at_ms
      - duration_ms
      - wrapped_key_b64
      - nonce_b64
      - aad_b64
      - sender_eph_public_b64
      - signature_b64
      - content_length
      title: SegmentBeginInput
      description: 'Envelope metadata for a segment whose ciphertext will be PUT

        directly to GCS via a signed URL (Phase 5b, migration 0094). Same

        envelope shape as ``SegmentUploadInput`` minus ``ciphertext_b64``

        — the bytes go GCS-direct, not through Cloud Run.


        ``content_length`` is the EXACT byte count of the ciphertext the

        client will PUT. The signed URL is bound to this length via GCS''s

        ``x-goog-content-length-range`` header so a misbehaving client (or

        a stolen URL) can''t push a multi-GB blob to the bucket. Must be

        > 0 and <= MAX_SEGMENT_BYTES.'
    SegmentBeginResult:
      properties:
        segment_id:
          type: string
          format: uuid
          title: Segment Id
        object_key:
          type: string
          title: Object Key
        upload_url:
          type: string
          title: Upload Url
        upload_method:
          type: string
          title: Upload Method
          default: PUT
        upload_content_type:
          type: string
          title: Upload Content Type
          default: application/octet-stream
        expires_at:
          type: string
          format: date-time
          title: Expires At
      type: object
      required:
      - segment_id
      - object_key
      - upload_url
      - expires_at
      title: SegmentBeginResult
      description: 'Server hands the client a signed URL to PUT the AEAD ciphertext

        to GCS directly. Client then POSTs ``/segments/{id}/finalize`` to

        publish the ``CallSegmentUploaded`` event.


        Why a two-step (begin → PUT → finalize) instead of letting GCS

        Pub/Sub fire the event on object-create: the Pub/Sub setup is

        operationally heavier (subscription, IAM, dead-letter topic) and

        has minutes-of-latency tail-cases; explicit finalize keeps the

        flow predictable.'
    SegmentUploadInput:
      properties:
        started_at_ms:
          type: integer
          minimum: 0.0
          title: Started At Ms
        duration_ms:
          type: integer
          maximum: 60000.0
          minimum: 1.0
          title: Duration Ms
        wrapped_key_b64:
          type: string
          title: Wrapped Key B64
        ciphertext_b64:
          type: string
          title: Ciphertext B64
        nonce_b64:
          type: string
          title: Nonce B64
        aad_b64:
          type: string
          title: Aad B64
        sender_eph_public_b64:
          type: string
          title: Sender Eph Public B64
        signature_b64:
          type: string
          title: Signature B64
        envelope_version:
          type: integer
          title: Envelope Version
          default: 1
      type: object
      required:
      - started_at_ms
      - duration_ms
      - wrapped_key_b64
      - ciphertext_b64
      - nonce_b64
      - aad_b64
      - sender_eph_public_b64
      - signature_b64
      title: SegmentUploadInput
      description: 'Same envelope shape as a normal message — see

        api/messages.py::SendMessageInput. Fields kept inline rather than

        importing the message type to keep call/message coupling loose.


        `wrapped_key_b64` is the AEAD session key wrapped to the workspace''s

        AI processor pubkey via ECDH (`crypto.wrap_session_key`). The AI

        digest worker unwraps it to decrypt the audio.'
    SegmentUploadResult:
      properties:
        segment_id:
          type: string
          format: uuid
          title: Segment Id
      type: object
      required:
      - segment_id
      title: SegmentUploadResult
    SendMessageResult:
      properties:
        message_id:
          type: string
          format: uuid
          title: Message Id
        server_received_at:
          type: string
          format: date-time
          title: Server Received At
        delivered_to_devices:
          items:
            type: string
            format: uuid
          type: array
          title: Delivered To Devices
        queued_for_devices:
          items:
            type: string
            format: uuid
          type: array
          title: Queued For Devices
      type: object
      required:
      - message_id
      - server_received_at
      - delivered_to_devices
      - queued_for_devices
      title: SendMessageResult
      description: 'Server -> client: confirmation of a delivered message.'
    ServiceTile:
      properties:
        name:
          type: string
          title: Name
        status:
          type: string
          title: Status
        primary:
          type: string
          title: Primary
        secondary:
          anyOf:
          - type: string
          - type: 'null'
          title: Secondary
        detail:
          additionalProperties: true
          type: object
          title: Detail
        dashboard_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Dashboard Url
      additionalProperties: false
      type: object
      required:
      - name
      - status
      - primary
      - secondary
      - detail
      - dashboard_url
      title: ServiceTile
    ShareCreateRequest:
      properties:
        kind:
          type: string
          maxLength: 32
          minLength: 2
          title: Kind
        title:
          anyOf:
          - type: string
            maxLength: 200
          - type: 'null'
          title: Title
        payload:
          additionalProperties: true
          type: object
          title: Payload
        expires_in_hours:
          anyOf:
          - type: integer
            maximum: 720.0
            minimum: 1.0
          - type: 'null'
          title: Expires In Hours
          default: 168
        view_limit:
          anyOf:
          - type: integer
            maximum: 10000.0
            minimum: 1.0
          - type: 'null'
          title: View Limit
      type: object
      required:
      - kind
      - payload
      title: ShareCreateRequest
      description: "Body for POST /v1/share. The `payload` shape varies by `kind`:\n\n  brief        \
        \     → {\"date\": \"YYYY-MM-DD\", \"highlights\": [...], \"actions\": [...]}\n  handoff_receipt\
        \   → {\"message_id\": \"...\", \"events\": [...], \"viewed_for_seconds\": ...}\n  ask_result\
        \        → {\"question\": \"...\", \"answer\": \"...\", \"sources\": [...]}\n  summary       \
        \    → {\"text\": \"...\", \"language\": \"en\"}\n  transcript        → {\"text\": \"...\", \"\
        language\": \"ar\"}\n\nThe renderer falls through to a generic JSON-pretty view when the\nkind\
        \ is unrecognised so we can ship new shapes server-side without\nblocking older clients."
    ShareCreateResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        slug:
          type: string
          title: Slug
        public_url:
          type: string
          title: Public Url
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
      type: object
      required:
      - id
      - slug
      - public_url
      - expires_at
      title: ShareCreateResponse
    ShareItem:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        slug:
          type: string
          title: Slug
        kind:
          type: string
          title: Kind
        title:
          anyOf:
          - type: string
          - type: 'null'
          title: Title
        public_url:
          type: string
          title: Public Url
        view_count:
          type: integer
          title: View Count
        view_limit:
          anyOf:
          - type: integer
          - type: 'null'
          title: View Limit
        expires_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Expires At
        revoked_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Revoked At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - slug
      - kind
      - title
      - public_url
      - view_count
      - view_limit
      - expires_at
      - revoked_at
      - created_at
      title: ShareItem
    ShareListResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/ShareItem'
          type: array
          title: Items
      type: object
      required:
      - items
      title: ShareListResponse
    SignInInput:
      properties:
        email:
          type: string
          format: email
          title: Email
        password:
          type: string
          title: Password
        device_id:
          type: string
          format: uuid
          title: Device Id
          description: The device the user is signing in from
      type: object
      required:
      - email
      - password
      - device_id
      title: SignInInput
    SignInOutput:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        device_id:
          type: string
          format: uuid
          title: Device Id
        access_token:
          type: string
          title: Access Token
        refresh_token:
          type: string
          title: Refresh Token
        access_expires_at:
          type: string
          format: date-time
          title: Access Expires At
        refresh_expires_at:
          type: string
          format: date-time
          title: Refresh Expires At
      type: object
      required:
      - user_id
      - device_id
      - access_token
      - refresh_token
      - access_expires_at
      - refresh_expires_at
      title: SignInOutput
    SignOutAllResponse:
      properties:
        revoked_device_ids:
          items:
            type: string
            format: uuid
          type: array
          title: Revoked Device Ids
      type: object
      required:
      - revoked_device_ids
      title: SignOutAllResponse
    SignUpInput:
      properties:
        email:
          type: string
          format: email
          title: Email
        password:
          type: string
          maxLength: 200
          minLength: 10
          title: Password
        display_name:
          type: string
          maxLength: 120
          minLength: 1
          title: Display Name
      type: object
      required:
      - email
      - password
      - display_name
      title: SignUpInput
    SignUpOutput:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
      type: object
      required:
      - user_id
      - display_name
      - workspace_id
      title: SignUpOutput
    SnoozeRequest:
      properties:
        until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Until
        minutes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Minutes
      type: object
      title: SnoozeRequest
    StarredMessageView:
      properties:
        message_id:
          type: string
          format: uuid
          title: Message Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        starred_at:
          type: string
          format: date-time
          title: Starred At
      type: object
      required:
      - message_id
      - thread_id
      - starred_at
      title: StarredMessageView
    StartCallInput:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        client_capability_mode:
          type: string
          title: Client Capability Mode
          default: single_peer_only
        invitee_user_ids:
          anyOf:
          - items:
              type: string
              format: uuid
            type: array
          - type: 'null'
          title: Invitee User Ids
      type: object
      required:
      - thread_id
      title: StartCallInput
    StatementsResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Items
      type: object
      required:
      - items
      title: StatementsResponse
      description: 'Hidden statements review surface.


        Rows the agent classified as ``is_actionable=False`` — passing

        remarks, observations, transcription junk. Surfaced under a

        "Hidden statements" toggle in the iOS Settings → Work surface, so

        the user can verify the agent''s calls and reverse a decision if

        needed.'
    SubpoenaCreateRequest:
      properties:
        target_tenant_fingerprint_hex:
          type: string
          maxLength: 64
          minLength: 64
          title: Target Tenant Fingerprint Hex
        target_tenant_display_name:
          type: string
          maxLength: 200
          minLength: 1
          title: Target Tenant Display Name
        scope:
          type: string
          maxLength: 4000
          minLength: 1
          title: Scope
        justification:
          type: string
          maxLength: 4000
          minLength: 1
          title: Justification
        deadline:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Deadline
      additionalProperties: false
      type: object
      required:
      - target_tenant_fingerprint_hex
      - target_tenant_display_name
      - scope
      - justification
      title: SubpoenaCreateRequest
      description: Payload for the control-plane caller composing a new request.
    SubpoenaCreateResponse:
      properties:
        entry:
          $ref: '#/components/schemas/SubpoenaOut'
      additionalProperties: false
      type: object
      required:
      - entry
      title: SubpoenaCreateResponse
    SubpoenaDecideRequest:
      properties:
        decision:
          type: string
          title: Decision
          description: '`approved` | `denied`'
        reason:
          anyOf:
          - type: string
            maxLength: 2000
          - type: 'null'
          title: Reason
      additionalProperties: false
      type: object
      required:
      - decision
      title: SubpoenaDecideRequest
      description: Payload for the tenant ComplianceOfficer's approve/deny call.
    SubpoenaListResponse:
      properties:
        entries:
          items:
            $ref: '#/components/schemas/SubpoenaOut'
          type: array
          title: Entries
        total:
          type: integer
          title: Total
      additionalProperties: false
      type: object
      required:
      - entries
      - total
      title: SubpoenaListResponse
    SubpoenaOut:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        target_tenant_fingerprint_hex:
          type: string
          title: Target Tenant Fingerprint Hex
        target_tenant_display_name:
          type: string
          title: Target Tenant Display Name
        requester_actor:
          type: string
          title: Requester Actor
        scope:
          type: string
          title: Scope
        justification:
          type: string
          title: Justification
        deadline:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Deadline
        status:
          type: string
          title: Status
        decided_by_actor:
          anyOf:
          - type: string
          - type: 'null'
          title: Decided By Actor
        decided_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Decided At
        decision_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Decision Reason
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - id
      - target_tenant_fingerprint_hex
      - target_tenant_display_name
      - requester_actor
      - scope
      - justification
      - deadline
      - status
      - decided_by_actor
      - decided_at
      - decision_reason
      - created_at
      - updated_at
      title: SubpoenaOut
    SubscriptionStatusResponse:
      properties:
        tier:
          type: string
          title: Tier
        expires_date_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Expires Date Ms
        auto_renew_status:
          type: boolean
          title: Auto Renew Status
        environment:
          anyOf:
          - type: string
          - type: 'null'
          title: Environment
        product_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Product Id
        last_verified_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Verified At
      type: object
      required:
      - tier
      - expires_date_ms
      - auto_renew_status
      - environment
      - product_id
      - last_verified_at
      title: SubscriptionStatusResponse
    SubscriptionsSnapshot:
      properties:
        as_of:
          type: string
          format: date-time
          title: As Of
        window:
          type: string
          title: Window
        users_total:
          type: integer
          title: Users Total
        users_by_tier:
          additionalProperties:
            type: integer
          type: object
          title: Users By Tier
        paid_users:
          type: integer
          title: Paid Users
        free_users:
          type: integer
          title: Free Users
        internal_users:
          type: integer
          title: Internal Users
        new_signups_window:
          type: integer
          title: New Signups Window
        churned_window:
          type: integer
          title: Churned Window
        workspaces_total:
          type: integer
          title: Workspaces Total
        workspaces_by_tier:
          additionalProperties:
            type: integer
          type: object
          title: Workspaces By Tier
      type: object
      required:
      - as_of
      - window
      - users_total
      - users_by_tier
      - paid_users
      - free_users
      - internal_users
      - new_signups_window
      - churned_window
      - workspaces_total
      - workspaces_by_tier
      title: SubscriptionsSnapshot
    SupervisoryExportView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        status:
          $ref: '#/components/schemas/ExportStatus'
        report_kind:
          type: string
          title: Report Kind
        case_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Case Id
        bundle_hash_hex:
          anyOf:
          - type: string
          - type: 'null'
          title: Bundle Hash Hex
        object_key:
          anyOf:
          - type: string
          - type: 'null'
          title: Object Key
        manifest:
          additionalProperties: true
          type: object
          title: Manifest
        failure_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Failure Reason
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - status
      - report_kind
      - case_id
      - bundle_hash_hex
      - object_key
      - manifest
      - failure_reason
      - created_at
      title: SupervisoryExportView
    TaskCreatorRunView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        user_id:
          type: string
          format: uuid
          title: User Id
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        started_at:
          type: string
          format: date-time
          title: Started At
        completed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Completed At
        success:
          type: boolean
          title: Success
        candidates_total:
          type: integer
          title: Candidates Total
        candidates_created:
          type: integer
          title: Candidates Created
        candidates_queued:
          type: integer
          title: Candidates Queued
        candidates_statement:
          type: integer
          title: Candidates Statement
        candidates_duplicate:
          type: integer
          title: Candidates Duplicate
        candidates_dropped:
          type: integer
          title: Candidates Dropped
        latency_ms:
          type: integer
          title: Latency Ms
        cache_hit_ratio:
          type: number
          title: Cache Hit Ratio
        model_used:
          type: string
          title: Model Used
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
        trace:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Trace
      type: object
      required:
      - id
      - user_id
      - message_id
      - thread_id
      - started_at
      - completed_at
      - success
      - candidates_total
      - candidates_created
      - candidates_queued
      - candidates_statement
      - candidates_duplicate
      - candidates_dropped
      - latency_ms
      - cache_hit_ratio
      - model_used
      - error
      - trace
      title: TaskCreatorRunView
      description: 'Operator-tier view of a single agent run.


        Surfaced via ``/v1/tasks/runs/{id}``. The iOS app

        never hits this — it''s for the operator console + audit harness.'
    TaskMutationResponse:
      properties:
        task:
          $ref: '#/components/schemas/TaskView'
      type: object
      required:
      - task
      title: TaskMutationResponse
    TaskReasoningView:
      properties:
        task_id:
          type: string
          format: uuid
          title: Task Id
        confidence_score:
          type: number
          title: Confidence Score
        is_actionable:
          type: boolean
          title: Is Actionable
        requires_confirmation:
          type: boolean
          title: Requires Confirmation
        agent_reasoning:
          type: string
          title: Agent Reasoning
        evidence_span:
          type: string
          title: Evidence Span
        suggested_actions:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Suggested Actions
        agent_run_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Agent Run Id
        run_summary:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Run Summary
      type: object
      required:
      - task_id
      - confidence_score
      - is_actionable
      - requires_confirmation
      - agent_reasoning
      - evidence_span
      - suggested_actions
      - agent_run_id
      title: TaskReasoningView
    TaskSnippet:
      properties:
        task_id:
          type: string
          format: uuid
          title: Task Id
        title:
          type: string
          title: Title
        due_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Due At
        is_promise:
          type: boolean
          title: Is Promise
        direction:
          anyOf:
          - type: string
          - type: 'null'
          title: Direction
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
      type: object
      required:
      - task_id
      - title
      - due_at
      - is_promise
      - direction
      - thread_id
      title: TaskSnippet
    TaskUpdateRequest:
      properties:
        due_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Due At
        priority:
          anyOf:
          - type: string
          - type: 'null'
          title: Priority
        title:
          anyOf:
          - type: string
          - type: 'null'
          title: Title
      type: object
      title: TaskUpdateRequest
      description: Partial update for a task. None means "leave the field alone.
    TaskView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        message_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Message Id
        thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Thread Id
        title:
          type: string
          title: Title
        due_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Due At
        priority:
          type: string
          title: Priority
        status:
          type: string
          title: Status
        source:
          type: string
          title: Source
        completed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Completed At
        created_at:
          type: string
          format: date-time
          title: Created At
        creator_user_id:
          type: string
          format: uuid
          title: Creator User Id
        creator_display_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Creator Display Name
        is_promise:
          type: boolean
          title: Is Promise
          default: false
        promise_direction:
          anyOf:
          - type: string
          - type: 'null'
          title: Promise Direction
        confidence_score:
          type: number
          title: Confidence Score
          default: 1.0
        agent_reasoning:
          type: string
          title: Agent Reasoning
          default: ''
        evidence_span:
          type: string
          title: Evidence Span
          default: ''
        is_actionable:
          type: boolean
          title: Is Actionable
          default: true
        requires_confirmation:
          type: boolean
          title: Requires Confirmation
          default: false
        suggested_actions:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Suggested Actions
          default: []
        depends_on_task_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Depends On Task Id
        agent_run_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Agent Run Id
        mention_count:
          type: integer
          title: Mention Count
          default: 1
      type: object
      required:
      - id
      - workspace_id
      - message_id
      - title
      - due_at
      - priority
      - status
      - source
      - completed_at
      - created_at
      - creator_user_id
      title: TaskView
    TasksDebugResponse:
      properties:
        total:
          type: integer
          title: Total
        open_count:
          type: integer
          title: Open Count
        by_status:
          additionalProperties:
            type: integer
          type: object
          title: By Status
        sample:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Sample
      type: object
      required:
      - total
      - open_count
      - by_status
      - sample
      title: TasksDebugResponse
    TasksGroupedResponse:
      properties:
        overdue:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Overdue
        today:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Today
        tomorrow:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Tomorrow
        this_week:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: This Week
        later:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Later
        no_date:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: No Date
        completed:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Completed
        pending_confirmation:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Pending Confirmation
          default: []
        statements:
          items:
            $ref: '#/components/schemas/TaskView'
          type: array
          title: Statements
          default: []
      type: object
      required:
      - overdue
      - today
      - tomorrow
      - this_week
      - later
      - no_date
      - completed
      title: TasksGroupedResponse
      description: 'Server-side grouping so the iOS Work tab is one fetch + render.


        Each group is a list (possibly empty). Pre-grouped on the server because

        the day-boundary math depends on the caller''s timezone, which we don''t

        have today (UTC for now); also cheaper than re-grouping on the client

        every time the timeline scrolls.'
    TenantHealthResponse:
      properties:
        status:
          type: string
          title: Status
        checks:
          additionalProperties: true
          type: object
          title: Checks
      type: object
      required:
      - status
      - checks
      title: TenantHealthResponse
    ThreadAIOutput:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        ai_processing_override:
          anyOf:
          - type: string
          - type: 'null'
          title: Ai Processing Override
      type: object
      required:
      - thread_id
      - ai_processing_override
      title: ThreadAIOutput
    ThreadAIProcessor:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        encryption_public_key_b64:
          type: string
          title: Encryption Public Key B64
      type: object
      required:
      - device_id
      - encryption_public_key_b64
      title: ThreadAIProcessor
      description: The AI processor identity for a thread's workspace (public-only).
    ThreadAskCitation:
      properties:
        kind:
          type: string
          title: Kind
          default: call_transcript
        call_summary_message_id:
          type: string
          format: uuid
          title: Call Summary Message Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        call_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Call Id
        transcript_span:
          additionalProperties:
            type: integer
          type: object
          title: Transcript Span
        snippet:
          type: string
          title: Snippet
        evidence:
          additionalProperties: true
          type: object
          title: Evidence
      type: object
      required:
      - call_summary_message_id
      - thread_id
      - transcript_span
      - snippet
      title: ThreadAskCitation
    ThreadAskRequest:
      properties:
        question:
          type: string
          maxLength: 400
          minLength: 2
          title: Question
      type: object
      required:
      - question
      title: ThreadAskRequest
    ThreadAskResponse:
      properties:
        question:
          type: string
          title: Question
        answer:
          type: string
          title: Answer
        citations:
          items:
            $ref: '#/components/schemas/ThreadAskCitation'
          type: array
          title: Citations
        no_data:
          type: boolean
          title: No Data
          default: false
      type: object
      required:
      - question
      - answer
      - citations
      title: ThreadAskResponse
    ThreadAssistByVoiceRequest:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        audio_b64:
          type: string
          maxLength: 8388608
          minLength: 1
          title: Audio B64
          description: Base64-encoded recording. WAV PCM Int16 mono 16 kHz preferred.
        audio_mime:
          type: string
          maxLength: 64
          title: Audio Mime
          description: MIME type of the audio bytes (e.g. "audio/wav").
          default: audio/wav
        hint_language:
          anyOf:
          - type: string
            maxLength: 12
          - type: 'null'
          title: Hint Language
          description: Optional BCP-47 / ISO-639-1 hint to bias the transcriber. Falls back to the caller's
            preferred language when omitted.
        participants:
          items:
            type: string
          type: array
          maxItems: 20
          title: Participants
        context:
          items:
            $ref: '#/components/schemas/_ContextMessage'
          type: array
          maxItems: 50
          title: Context
      type: object
      required:
      - thread_id
      - audio_b64
      title: ThreadAssistByVoiceRequest
      description: 'Voice variant of ``ThreadAssistRequest`` — server transcribes.


        Same contract as the text endpoint, but the question is delivered

        as a base64-encoded WAV. The server uses the production

        ``GemmaAudioTranscriber`` to turn it into text, emits the

        transcript as the first SSE event so the client can render the

        question bubble, then proceeds with the normal assistant stream.'
    ThreadAssistRequest:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        question:
          type: string
          maxLength: 1000
          minLength: 1
          title: Question
        participants:
          items:
            type: string
          type: array
          maxItems: 20
          title: Participants
          description: Display names of all thread participants in the order the iOS client would render
            them. The asking user's name is ALWAYS first; peers follow. Used to make the LLM's responses
            sound natural about who said what.
        context:
          items:
            $ref: '#/components/schemas/_ContextMessage'
          type: array
          maxItems: 50
          title: Context
          description: Recent messages in the thread, oldest → newest. The LLM uses these as conversational
            context for the answer.
      type: object
      required:
      - thread_id
      - question
      title: ThreadAssistRequest
    ThreadCreateInput:
      properties:
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        type:
          type: string
          pattern: ^(self|direct|group|imported)$
          title: Type
        member_user_ids:
          items:
            type: string
            format: uuid
          type: array
          title: Member User Ids
        title:
          anyOf:
          - type: string
          - type: 'null'
          title: Title
      type: object
      required:
      - workspace_id
      - type
      title: ThreadCreateInput
      description: 'Client -> server: create a thread.'
    ThreadEventView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        actor_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Actor User Id
        event_type:
          type: string
          title: Event Type
        payload:
          additionalProperties: true
          type: object
          title: Payload
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - thread_id
      - actor_user_id
      - event_type
      - payload
      - created_at
      title: ThreadEventView
      description: Visible system event for group-management history.
    ThreadMuteInput:
      properties:
        muted_until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Muted Until
          description: Exclusive upper bound. NULL = mute forever (until unmute).
      type: object
      title: ThreadMuteInput
    ThreadParticipantView:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        role:
          type: string
          title: Role
          default: member
        accepted_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Accepted At
        joined_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Joined At
        history_visible_after:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: History Visible After
      type: object
      required:
      - user_id
      title: ThreadParticipantView
      description: One active human member in a thread.
    ThreadPatchInput:
      properties:
        title:
          anyOf:
          - type: string
            maxLength: 80
          - type: 'null'
          title: Title
      type: object
      title: ThreadPatchInput
    ThreadRequestView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        type:
          type: string
          title: Type
        title:
          anyOf:
          - type: string
          - type: 'null'
          title: Title
        inviter_user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Inviter User Id
        inviter_display_name:
          type: string
          title: Inviter Display Name
        invited_at:
          type: string
          format: date-time
          title: Invited At
      type: object
      required:
      - id
      - workspace_id
      - type
      - title
      - inviter_user_id
      - inviter_display_name
      - invited_at
      title: ThreadRequestView
      description: A pending thread invitation the caller can accept or decline.
    ThreadSnippet:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        thread_title:
          anyOf:
          - type: string
          - type: 'null'
          title: Thread Title
        last_message_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Message At
        sender_display_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Sender Display Name
        intent_summary:
          anyOf:
          - type: string
          - type: 'null'
          title: Intent Summary
        summary_short:
          anyOf:
          - type: string
          - type: 'null'
          title: Summary Short
        is_voice:
          type: boolean
          title: Is Voice
        has_open_questions:
          type: boolean
          title: Has Open Questions
      type: object
      required:
      - thread_id
      - thread_title
      - last_message_at
      - sender_display_name
      - intent_summary
      - summary_short
      - is_voice
      - has_open_questions
      title: ThreadSnippet
    ThreadView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        type:
          type: string
          title: Type
        title:
          anyOf:
          - type: string
          - type: 'null'
          title: Title
        last_message_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Message At
        member_user_ids:
          items:
            type: string
            format: uuid
          type: array
          title: Member User Ids
        participants:
          items:
            $ref: '#/components/schemas/ThreadParticipantView'
          type: array
          title: Participants
        ai_processor:
          anyOf:
          - $ref: '#/components/schemas/ThreadAIProcessor'
          - type: 'null'
        ai_processing_override:
          anyOf:
          - type: string
          - type: 'null'
          title: Ai Processing Override
        last_message_preview:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Message Preview
        last_message_content_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Message Content Type
        last_message_duration_seconds:
          anyOf:
          - type: number
          - type: 'null'
          title: Last Message Duration Seconds
        last_message_sent_by_self:
          type: boolean
          title: Last Message Sent By Self
          default: false
        unread_count:
          type: integer
          title: Unread Count
          default: 0
        open_promises_in_thread:
          type: integer
          title: Open Promises In Thread
          default: 0
        disappearing_after_seconds:
          anyOf:
          - type: integer
          - type: 'null'
          title: Disappearing After Seconds
        muted_until:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Muted Until
        peer_subscription_tier:
          anyOf:
          - type: string
          - type: 'null'
          title: Peer Subscription Tier
        peer_ai_enabled:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Peer Ai Enabled
      type: object
      required:
      - id
      - workspace_id
      - type
      - title
      - last_message_at
      - member_user_ids
      title: ThreadView
      description: 'Server -> client: thread summary.'
    TopTenant:
      properties:
        workspace_id:
          type: string
          title: Workspace Id
        display_name:
          type: string
          title: Display Name
        messages_24h:
          type: integer
          title: Messages 24H
        calls_24h:
          type: integer
          title: Calls 24H
      additionalProperties: false
      type: object
      required:
      - workspace_id
      - display_name
      - messages_24h
      - calls_24h
      title: TopTenant
    TranscriptionEditRequest:
      properties:
        new_transcript:
          type: string
          maxLength: 20000
          minLength: 1
          title: New Transcript
      type: object
      required:
      - new_transcript
      title: TranscriptionEditRequest
      description: 'Body for PATCH /v1/messages/{id}/transcription.


        The caller updates the server-readable transcript text of a voice /

        audio message. The audio bytes stay untouched; only

        ``ai_payload.transcript`` (and the cached translation) change.

        Every edit appends an immutable row to ``message_edits`` for audit

        + ML use; ``thread_call_rag`` and other downstream consumers pick

        up the new text on the next read.'
    TranslateStreamRequest:
      properties:
        target_lang:
          anyOf:
          - type: string
          - type: 'null'
          title: Target Lang
      type: object
      title: TranslateStreamRequest
      description: 'Optional request body for translate-stream.


        The iOS client sends ``target_lang`` to authoritatively pin the

        translation to the user''s *device-local* preferred language —

        this avoids a class of bugs where the user picked a new language

        in Settings, the PATCH /v1/me write failed, and subsequent

        translations came back in the OLD language because the server

        was reading the stale DB value (VD-AI-LANG, 2026-05-09).


        All fields are optional; the server falls through to the

        DB-resolved language when ``target_lang`` is absent.'
    TrustAIProcessor:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        fingerprint:
          type: string
          title: Fingerprint
        label:
          type: string
          title: Label
          default: AI Processor
      type: object
      required:
      - device_id
      - fingerprint
      title: TrustAIProcessor
    TrustDeviceView:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        label:
          type: string
          title: Label
        platform:
          type: string
          title: Platform
        last_seen_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Seen At
        created_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Created At
        fingerprint:
          type: string
          title: Fingerprint
        is_current:
          type: boolean
          title: Is Current
          default: false
      type: object
      required:
      - device_id
      - label
      - platform
      - fingerprint
      title: TrustDeviceView
    TrustMemberView:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        is_self:
          type: boolean
          title: Is Self
          default: false
        devices:
          items:
            $ref: '#/components/schemas/TrustDeviceView'
          type: array
          title: Devices
      type: object
      required:
      - user_id
      - display_name
      - devices
      title: TrustMemberView
    TrustResponse:
      properties:
        thread_id:
          type: string
          format: uuid
          title: Thread Id
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        members:
          items:
            $ref: '#/components/schemas/TrustMemberView'
          type: array
          title: Members
        workspace_ai_mode:
          type: string
          title: Workspace Ai Mode
        thread_ai_override:
          anyOf:
          - type: string
          - type: 'null'
          title: Thread Ai Override
        ai_processor:
          anyOf:
          - $ref: '#/components/schemas/TrustAIProcessor'
          - type: 'null'
        messages_total:
          type: integer
          title: Messages Total
        messages_ai_seen:
          type: integer
          title: Messages Ai Seen
      type: object
      required:
      - thread_id
      - workspace_id
      - members
      - workspace_ai_mode
      - messages_total
      - messages_ai_seen
      title: TrustResponse
    UpdateMeRequest:
      properties:
        display_name:
          anyOf:
          - type: string
            maxLength: 120
            minLength: 1
          - type: 'null'
          title: Display Name
        preferred_language:
          anyOf:
          - type: string
            maxLength: 8
            minLength: 2
          - type: 'null'
          title: Preferred Language
        morning_brief_minutes:
          anyOf:
          - type: integer
            maximum: 1439.0
            minimum: -1.0
          - type: 'null'
          title: Morning Brief Minutes
        morning_brief_tz:
          anyOf:
          - type: string
            maxLength: 64
          - type: 'null'
          title: Morning Brief Tz
        transcription_language_pref:
          anyOf:
          - type: string
            maxLength: 32
          - type: 'null'
          title: Transcription Language Pref
        selected_voice_id:
          anyOf:
          - type: string
            maxLength: 64
          - type: 'null'
          title: Selected Voice Id
        task_extraction_enabled:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Task Extraction Enabled
      type: object
      title: UpdateMeRequest
      description: 'Subset of profile fields the user is allowed to edit themselves.

        Email/phone changes flow through different paths (re-verify) so

        they don''t end up here. `display_name` and `preferred_language` are

        fully self-serve; `avatar_object_key` is set by the avatar-upload

        endpoint (POST /v1/me/avatar) and isn''t accepted here.'
    UpdateMeResponse:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        preferred_language:
          type: string
          title: Preferred Language
        transcription_language_pref:
          anyOf:
          - type: string
          - type: 'null'
          title: Transcription Language Pref
        task_extraction_enabled:
          type: boolean
          title: Task Extraction Enabled
          default: true
      type: object
      required:
      - user_id
      - display_name
      - preferred_language
      title: UpdateMeResponse
    UpdatePushTokenInput:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        push_token:
          type: string
          maxLength: 4096
          minLength: 8
          title: Push Token
        apns_env:
          anyOf:
          - type: string
            maxLength: 16
          - type: 'null'
          title: Apns Env
      type: object
      required:
      - device_id
      - push_token
      title: UpdatePushTokenInput
    UpdatePushTokenOutput:
      properties:
        updated:
          type: boolean
          title: Updated
      type: object
      required:
      - updated
      title: UpdatePushTokenOutput
    UpdateThreadAIInput:
      properties:
        override:
          type: string
          enum:
          - 'off'
          - ''
          title: Override
      type: object
      required:
      - override
      title: UpdateThreadAIInput
    UpdateVoIPPushTokenInput:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        voip_token:
          type: string
          maxLength: 4096
          minLength: 8
          title: Voip Token
        apns_env:
          anyOf:
          - type: string
            maxLength: 16
          - type: 'null'
          title: Apns Env
      type: object
      required:
      - device_id
      - voip_token
      title: UpdateVoIPPushTokenInput
    UpdateWaveLinkEndpointInput:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        wan_host:
          type: string
          maxLength: 64
          minLength: 1
          title: Wan Host
        wan_port:
          type: integer
          maximum: 65535.0
          minimum: 1.0
          title: Wan Port
      type: object
      required:
      - device_id
      - wan_host
      - wan_port
      title: UpdateWaveLinkEndpointInput
    UpdateWaveLinkEndpointOutput:
      properties:
        updated:
          type: boolean
          title: Updated
      type: object
      required:
      - updated
      title: UpdateWaveLinkEndpointOutput
    UpdateWaveLinkKeyInput:
      properties:
        device_id:
          type: string
          format: uuid
          title: Device Id
        wavelink_noise_pub_b64:
          type: string
          maxLength: 64
          minLength: 32
          title: Wavelink Noise Pub B64
      type: object
      required:
      - device_id
      - wavelink_noise_pub_b64
      title: UpdateWaveLinkKeyInput
    UpdateWaveLinkKeyOutput:
      properties:
        updated:
          type: boolean
          title: Updated
      type: object
      required:
      - updated
      title: UpdateWaveLinkKeyOutput
    UpdateWorkspaceAIModeInput:
      properties:
        mode:
          type: string
          enum:
          - 'off'
          - summarize
          - remember
          title: Mode
      type: object
      required:
      - mode
      title: UpdateWorkspaceAIModeInput
    UserIdentityRequest:
      properties:
        user_identity_public_key_b64:
          type: string
          maxLength: 128
          minLength: 1
          title: User Identity Public Key B64
      type: object
      required:
      - user_identity_public_key_b64
      title: UserIdentityRequest
    UserIdentityResponse:
      properties:
        user_identity_public_key_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: User Identity Public Key B64
        rotated:
          type: boolean
          title: Rotated
      type: object
      required:
      - user_identity_public_key_b64
      - rotated
      title: UserIdentityResponse
    UserLookupResponse:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
        email:
          anyOf:
          - type: string
          - type: 'null'
          title: Email
        phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Phone
        user_identity_public_key_b64:
          anyOf:
          - type: string
          - type: 'null'
          title: User Identity Public Key B64
      type: object
      required:
      - user_id
      - display_name
      title: UserLookupResponse
    UserNameView:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        display_name:
          type: string
          title: Display Name
      type: object
      required:
      - user_id
      - display_name
      title: UserNameView
    UsersByIDsRequest:
      properties:
        user_ids:
          items:
            type: string
            format: uuid
          type: array
          title: User Ids
      type: object
      required:
      - user_ids
      title: UsersByIDsRequest
    UsersByIDsResponse:
      properties:
        users:
          items:
            $ref: '#/components/schemas/UserNameView'
          type: array
          title: Users
      type: object
      required:
      - users
      title: UsersByIDsResponse
    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
    VerifyReceiptRequest:
      properties:
        jws_receipt:
          type: string
          maxLength: 64000
          minLength: 20
          title: Jws Receipt
        paywall_disclosure_version:
          anyOf:
          - type: string
            maxLength: 64
          - type: 'null'
          title: Paywall Disclosure Version
      type: object
      required:
      - jws_receipt
      title: VerifyReceiptRequest
      description: 'Body for POST /v1/subscriptions/verify-receipt.


        iOS sends the JWS transaction token + the paywall disclosure version

        the user saw at the moment of purchase (ROSCA §3.9 auditability).'
    VerifyReceiptResponse:
      properties:
        tier:
          type: string
          title: Tier
        expires_date_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Expires Date Ms
        auto_renew_status:
          type: boolean
          title: Auto Renew Status
        environment:
          anyOf:
          - type: string
          - type: 'null'
          title: Environment
        product_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Product Id
        last_verified_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Verified At
      type: object
      required:
      - tier
      - expires_date_ms
      - auto_renew_status
      - environment
      - product_id
      - last_verified_at
      title: VerifyReceiptResponse
    VoiceCloneQuota:
      properties:
        daily_creates_remaining:
          type: integer
          title: Daily Creates Remaining
        daily_bytes_remaining:
          type: integer
          title: Daily Bytes Remaining
        lifetime_creates_remaining:
          type: integer
          title: Lifetime Creates Remaining
      type: object
      required:
      - daily_creates_remaining
      - daily_bytes_remaining
      - lifetime_creates_remaining
      title: VoiceCloneQuota
      description: 'Capacity remaining for the caller — displayed in iOS Settings.


        Numbers reflect the budgets configured in

        :mod:`telbox.modules.abuse`. Surfaced in the GET /voice-clones

        response so the picker can show "3 of 5 today" / "12 of 20 lifetime"

        without a second round-trip.'
    VoiceCloneResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        name:
          type: string
          title: Name
        language:
          type: string
          title: Language
        status:
          type: string
          title: Status
        estimated_seconds:
          anyOf:
          - type: integer
          - type: 'null'
          title: Estimated Seconds
        error_message:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Message
        created_at:
          type: string
          format: date-time
          title: Created At
        ready_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Ready At
      type: object
      required:
      - id
      - name
      - language
      - status
      - created_at
      title: VoiceCloneResponse
    VoiceItem:
      properties:
        id:
          type: string
          title: Id
        name:
          type: string
          title: Name
        personality:
          anyOf:
          - type: string
          - type: 'null'
          title: Personality
        languages:
          items:
            type: string
          type: array
          title: Languages
          default: []
        gender:
          type: string
          enum:
          - female
          - male
          - neutral
          - unknown
          title: Gender
          default: unknown
        kind:
          type: string
          enum:
          - builtin
          - clone
          title: Kind
          default: builtin
        status:
          type: string
          enum:
          - ready
          - pending
          - processing
          - failed
          title: Status
          default: ready
        created_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Created At
        error_message:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Message
      type: object
      required:
      - id
      - name
      title: VoiceItem
    VoiceListResponse:
      properties:
        voices:
          items:
            $ref: '#/components/schemas/VoiceItem'
          type: array
          title: Voices
        selected_voice_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Selected Voice Id
        quota:
          $ref: '#/components/schemas/VoiceCloneQuota'
      type: object
      required:
      - voices
      - quota
      title: VoiceListResponse
    WindowMeta:
      properties:
        since:
          type: string
          title: Since
        window_seconds:
          type: integer
          title: Window Seconds
        bucket_seconds:
          type: integer
          title: Bucket Seconds
      additionalProperties: false
      type: object
      required:
      - since
      - window_seconds
      - bucket_seconds
      title: WindowMeta
      description: Active historical window for the snapshot.
    WipeMemoryOutput:
      properties:
        people_deleted:
          type: integer
          title: People Deleted
        memory_items_deleted:
          type: integer
          title: Memory Items Deleted
      type: object
      required:
      - people_deleted
      - memory_items_deleted
      title: WipeMemoryOutput
    WordTiming:
      properties:
        word:
          type: string
          title: Word
        start_ms:
          type: integer
          title: Start Ms
        end_ms:
          type: integer
          title: End Ms
      type: object
      required:
      - word
      - start_ms
      - end_ms
      title: WordTiming
      description: 'Per-word timing for the brief narration''s karaoke highlight in

        iOS BriefingView. Emitted alongside ``audio_url`` in

        ``BriefingResponse`` — see the docstring on ``audio_word_timings``

        for the iOS contract.'
    WorkflowListResponse:
      properties:
        workflows:
          items:
            $ref: '#/components/schemas/WorkflowOut'
          type: array
          title: Workflows
        total:
          type: integer
          title: Total
        repo_slug:
          type: string
          title: Repo Slug
      additionalProperties: false
      type: object
      required:
      - workflows
      - total
      - repo_slug
      title: WorkflowListResponse
    WorkflowOut:
      properties:
        id:
          type: integer
          title: Id
        name:
          type: string
          title: Name
        path:
          type: string
          title: Path
        state:
          type: string
          title: State
        html_url:
          type: string
          title: Html Url
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      additionalProperties: false
      type: object
      required:
      - id
      - name
      - path
      - state
      - html_url
      - created_at
      - updated_at
      title: WorkflowOut
    WorkspaceAIModeOutput:
      properties:
        workspace_id:
          type: string
          format: uuid
          title: Workspace Id
        ai_processing_mode:
          type: string
          title: Ai Processing Mode
      type: object
      required:
      - workspace_id
      - ai_processing_mode
      title: WorkspaceAIModeOutput
    WorkspaceView:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        name:
          type: string
          title: Name
        privacy_tier:
          type: string
          title: Privacy Tier
        ai_processing_mode:
          type: string
          title: Ai Processing Mode
        plan:
          type: string
          title: Plan
        region:
          type: string
          title: Region
        ai_processor:
          anyOf:
          - $ref: '#/components/schemas/AIProcessorInfo'
          - type: 'null'
        echo_thread_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Echo Thread Id
      type: object
      required:
      - id
      - name
      - privacy_tier
      - ai_processing_mode
      - plan
      - region
      title: WorkspaceView
    _ContextMessage:
      properties:
        sender_display_name:
          type: string
          maxLength: 120
          title: Sender Display Name
        is_own:
          type: boolean
          title: Is Own
          description: True if the asking user sent this message. Lets the LLM phrase responses correctly
            ("you said" vs "Ahmed said").
          default: false
        sent_at:
          type: string
          format: date-time
          title: Sent At
        kind:
          type: string
          maxLength: 24
          title: Kind
          description: text | voice | image | file | location | call_summary
        snippet:
          type: string
          maxLength: 480
          title: Snippet
          description: 'Best-available textual representation of the message. Voice notes: send the AI
            transcript or summary if available. Images/files: a brief description ("image attached").
            Plain text: the text itself, truncated.'
      type: object
      required:
      - sender_display_name
      - sent_at
      - kind
      - snippet
      title: _ContextMessage
      description: One recent message in the thread, sender-attributed.
    Error:
      type: object
      title: Error
      properties:
        detail:
          type: string
          description: Machine-readable error code (e.g. `missing_bearer_token`, `ai_quota_exceeded_ask`).
            See the Errors guide.
      required:
      - detail
      example:
        detail: missing_bearer_token
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT access token from `POST /v1/auth/phone/verify` or `/v1/auth/refresh`.
  responses:
    Unauthorized:
      description: Missing, malformed, or expired bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Rate limit exceeded. Inspect the `Retry-After` header.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
servers:
- url: https://api.telbox.ai
  description: Production
security:
- bearerAuth: []
tags:
- name: auth
  description: Phone-OTP login, token refresh, and legacy email/password.
- name: devices
  description: Per-device registration, push tokens, and WaveLink keys.
- name: me
  description: The authenticated user's own profile, devices, and consent.
- name: users
  description: Look up other users by id or handle.
- name: founder-auth
  description: Founder/admin portal magic-link auth.
- name: threads
  description: 'Conversations: create, list, membership, lifecycle.'
- name: messages
  description: Send, fetch, edit, and search messages.
- name: messages_bulk
  description: Bulk message import.
- name: reactions
  description: Emoji reactions on messages.
- name: handoff_events
  description: Live read / screenshot receipts for hand-off messages.
- name: favorites
  description: Pinned threads and starred messages.
- name: contacts
  description: Contact matching and invite tracking.
- name: imports
  description: WhatsApp-to-Telbox import jobs.
- name: moderation
  description: Blocking and abuse reporting.
- name: ask
  description: Ask-anything RAG agent over your own history.
- name: agent
  description: Agent write-tool confirm/deny and ask history.
- name: thread_assistant
  description: In-thread private AI helper (stateless).
- name: personal_assistant
  description: Delegated executive assistant acting as the owner.
- name: insights
  description: On-demand AI insights for a message.
- name: translate
  description: Streaming transcript translation.
- name: memory
  description: People graph and semantic memory search.
- name: briefing
  description: Catch-me-up daily briefing.
- name: actions
  description: AI-suggested next-steps for the Work tab.
- name: tasks
  description: Extracted commitments, promises, and statements.
- name: calls
  description: Voice/group call state, signaling, and recordings.
- name: voice_clones
  description: 'Voice synthesis: create, list, preview voice clones.'
- name: realtime
  description: WebSocket event stream (and SSE streaming) — see the Realtime guide.
- name: media
  description: Encrypted blob upload and retrieval.
- name: backup
  description: Encrypted backup envelope (server stores ciphertext only).
- name: sharing
  description: Public share artifacts, invite landings, and anonymous voice drops.
- name: trust
  description: Per-thread Trust Center.
- name: directory
  description: Tenant trust + discovery directory.
- name: forensics
  description: Audio watermark verification.
- name: operator
  description: Enterprise operator console (cases, JIT, exports, audit).
- name: subpoenas
  description: Legal-process request intake and adjudication.
- name: subscriptions
  description: Apple StoreKit2 receipt verification and status.
- name: feature-flags-admin
  description: Feature-flag administration.
- name: admin-network-metrics
  description: Aggregate network counters (admin).
- name: admin-ops-dashboard
  description: Master operations dashboard (admin).
- name: admin-insights
  description: Business / compliance / security insights (admin).
- name: admin-audit
  description: Platform-level admin action audit log.
- name: admin-pipelines
  description: Workflow run inspection (admin).
- name: admin-ai-policy
  description: Tenant AI policy read/replace (admin).
- name: admin-ai-quota-override
  description: Per-user AI quota overrides (admin).
- name: docs-portal
  description: Live, admin-gated interactive API reference.
- name: health
  description: Liveness, readiness, and capability probes.
- name: metrics
  description: Prometheus exposition endpoint.
- name: runtime
  description: 'Hot-updatable client config: feature flags, copy, banners.'
- name: diagnostic
  description: Per-message and per-feature diagnostic introspection.
- name: settings
  description: Per-user and per-workspace preferences and AI mode.
x-tagGroups:
- name: Identity & Auth
  tags:
  - auth
  - devices
  - me
  - users
  - founder-auth
- name: Messaging
  tags:
  - threads
  - messages
  - messages_bulk
  - reactions
  - handoff_events
  - favorites
  - contacts
  - imports
  - moderation
- name: AI & Insights
  tags:
  - ask
  - agent
  - thread_assistant
  - personal_assistant
  - insights
  - translate
  - memory
  - briefing
  - actions
  - tasks
- name: Voice & Calls
  tags:
  - calls
  - voice_clones
- name: Realtime
  tags:
  - realtime
- name: Media & Sharing
  tags:
  - media
  - backup
  - sharing
- name: Trust & Directory
  tags:
  - trust
  - directory
  - forensics
- name: Compliance & Operator
  tags:
  - operator
  - subpoenas
- name: Billing
  tags:
  - subscriptions
- name: Admin & Ops
  tags:
  - feature-flags-admin
  - admin-network-metrics
  - admin-ops-dashboard
  - admin-insights
  - admin-audit
  - admin-pipelines
  - admin-ai-policy
  - admin-ai-quota-override
  - docs-portal
- name: System
  tags:
  - health
  - metrics
  - runtime
  - diagnostic
  - settings
