openapi: 3.0.3
info:
  title: Brief API v1
  version: 1.0.0
  description: Brief — Your Product Navigator. API for managing documents, decisions, folders, features, personas,
    conversations, and more.
  contact:
    email: support@briefhq.ai
servers:
  - url: https://app.briefhq.ai/api/v1
    description: Production
  - url: http://localhost:3000/api/v1
    description: Local development
security:
  - ApiKeyAuth: []
components:
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: API key authentication. Pass your API key as a Bearer token in the Authorization header.
    ClerkSession:
      type: apiKey
      in: cookie
      name: __session
      description: Clerk session cookie authentication (browser clients).
  schemas:
    ErrorResponseWithDetails:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
        resolution_hint:
          type: string
        details:
          type: object
          additionalProperties:
            nullable: true
      required:
        - error
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
        resolution_hint:
          type: string
      required:
        - error
    RateLimitedResponse:
      allOf:
        - $ref: "#/components/schemas/ErrorResponse"
        - type: object
          properties:
            retry_after:
              type: integer
              description: Seconds until the limit resets
          required:
            - retry_after
    DocumentListItem:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        slug:
          type: string
          nullable: true
        mime_type:
          type: string
          nullable: true
        file_size:
          type: number
          nullable: true
        category:
          type: string
          nullable: true
        updated_at:
          type: string
          nullable: true
        folder_id:
          type: string
          nullable: true
        folder_path:
          type: string
          nullable: true
        created_by:
          type: string
          nullable: true
        created_via_source:
          type: string
          nullable: true
        updated_by:
          type: string
          nullable: true
        last_edited_by:
          type: string
          nullable: true
      required:
        - id
        - title
    CursorPagination:
      allOf:
        - $ref: "#/components/schemas/Pagination"
        - type: object
          properties:
            next_cursor:
              type: string
              nullable: true
          required:
            - next_cursor
    Pagination:
      type: object
      properties:
        page:
          type: number
        limit:
          type: number
        hasMore:
          type: boolean
      required:
        - page
        - limit
        - hasMore
    Document:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        title:
          type: string
        content:
          nullable: true
        plaintext:
          type: string
          nullable: true
        markdown:
          type: string
          nullable: true
        category:
          type: string
          nullable: true
        created_by:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        storage_path:
          type: string
          nullable: true
        mime_type:
          type: string
          nullable: true
        file_size:
          type: number
          nullable: true
        folder_id:
          type: string
          nullable: true
        folder_path:
          type: string
          nullable: true
        deleted_at:
          type: string
          nullable: true
        signedUrl:
          type: string
          nullable: true
        revision:
          type: number
        created_via_source:
          type: string
          nullable: true
        updated_by:
          type: string
          nullable: true
        last_edited_by:
          type: string
          nullable: true
      required:
        - id
        - org_id
        - title
        - created_at
        - updated_at
    DocumentUpdated:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        folder_id:
          type: string
          nullable: true
        folder_path:
          type: string
          nullable: true
        category:
          type: string
          nullable: true
        updated_at:
          type: string
        edit_result:
          $ref: "#/components/schemas/EditResult"
        live_edit:
          type: boolean
          description: The body edit was applied and checkpointed through the active live editor room
        revision:
          type: number
          description: "BRI-4880: the document's new revision — carry it as base_revision on the next PATCH"
      required:
        - id
        - title
        - updated_at
    EditResult:
      type: object
      properties:
        status:
          type: string
          enum:
            - applied
            - already_applied
            - not_found
          description: applied — edit succeeded. already_applied — old_text not found but new_text already present (idempotent).
            not_found — neither found.
        match_offset:
          type: number
          description: Character offset of the match in the document
        context_before:
          type: string
          description: Up to 200 characters before the match
        context_after:
          type: string
          description: Up to 200 characters after the match
        suggestion:
          type: object
          nullable: true
          properties:
            text:
              type: string
              description: Closest matching substring in the document
            similarity:
              type: number
              description: Dice coefficient (0–1)
          required:
            - text
            - similarity
          description: Fuzzy match suggestion when status is not_found (>80% similarity)
      required:
        - status
      description: Present for edit operations only
    DocumentUpdateError:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
        resolution_hint:
          type: string
        details:
          type: object
          additionalProperties:
            nullable: true
        edit_result:
          allOf:
            - $ref: "#/components/schemas/EditResult"
            - description: Present for edit failures — includes status 'not_found' and optional fuzzy suggestion
        retryable:
          type: boolean
          description: When false, read the document before retrying an uncertain live write
        live_write_applied:
          type: boolean
          description: The live edit was applied, but its response could not be completed
      required:
        - error
    StaleWriteConflict:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
          description: "`stale_write` for a stale base_revision, `live_edit_metadata_conflict` for metadata bundled with an
            active-room body edit"
        resolution_hint:
          type: string
        details:
          type: object
          additionalProperties:
            nullable: true
        edit_result:
          allOf:
            - $ref: "#/components/schemas/EditResult"
            - description: Present for edit failures — includes status 'not_found' and optional fuzzy suggestion
        retryable:
          type: boolean
          description: When false, read the document before retrying an uncertain live write
        live_write_applied:
          type: boolean
          description: The live edit was applied, but its response could not be completed
        server_revision:
          type: number
        server_updated_at:
          type: string
          nullable: true
        last_edited_by:
          type: string
          nullable: true
        current_markdown:
          type: string
          description: The server's current markdown, for conflict resolution UX
      required:
        - error
    DocumentMoved:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        folder_id:
          type: string
          nullable: true
        folder_path:
          type: string
          nullable: true
        updated_at:
          type: string
      required:
        - id
        - title
        - folder_id
        - updated_at
    VersionSummary:
      type: object
      properties:
        id:
          type: string
        trigger:
          type: string
        created_by:
          type: string
          nullable: true
        actor_type:
          type: string
          nullable: true
        origin:
          type: string
          nullable: true
        chars_added:
          type: number
          nullable: true
        chars_removed:
          type: number
          nullable: true
        event_count:
          type: number
          nullable: true
        created_at:
          type: string
      required:
        - id
        - trigger
        - created_at
    DocumentCreated:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        title:
          type: string
        content:
          nullable: true
        folder_id:
          type: string
          nullable: true
        folder_path:
          type: string
          nullable: true
        category:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
        - id
        - org_id
        - title
        - folder_id
        - created_at
        - updated_at
    DocumentComment:
      type: object
      properties:
        id:
          type: string
        document_id:
          type: string
        parent_comment_id:
          type: string
          nullable: true
        body:
          type: string
        quote_text:
          type: string
          nullable: true
        quote_prefix:
          type: string
          nullable: true
        quote_suffix:
          type: string
          nullable: true
        mentioned_user_ids:
          type: array
          items:
            type: string
        status:
          type: string
          enum:
            - open
            - resolved
        resolved_at:
          type: string
          nullable: true
        resolved_by:
          type: string
          nullable: true
        actor_type:
          type: string
          enum:
            - user
            - agent
            - system
        created_by:
          type: string
        created_via_source:
          type: string
          nullable: true
        created_via_trigger:
          type: string
          nullable: true
        created_via_integration:
          type: string
          nullable: true
        agent_name:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
        - id
        - document_id
        - parent_comment_id
        - body
        - quote_text
        - quote_prefix
        - quote_suffix
        - mentioned_user_ids
        - status
        - resolved_at
        - resolved_by
        - actor_type
        - created_by
        - created_via_source
        - created_via_trigger
        - created_via_integration
        - agent_name
        - created_at
        - updated_at
    DocumentPresenceEntry:
      type: object
      properties:
        userId:
          type: string
        displayName:
          type: string
        mode:
          type: string
          enum:
            - viewing
            - editing
        lastSeenAt:
          type: number
          description: Epoch ms of the entry's last heartbeat
      required:
        - userId
        - displayName
        - mode
        - lastSeenAt
    DocumentPresenceHeartbeat:
      type: object
      properties:
        docId:
          type: string
          description: Must match the document id in the URL
        userId:
          type: string
          description: Must match the authenticated caller
        displayName:
          type: string
          minLength: 1
          maxLength: 120
        mode:
          type: string
          enum:
            - viewing
            - editing
      required:
        - docId
        - userId
        - displayName
        - mode
    FavoriteBody:
      type: object
      properties:
        favorite:
          type: boolean
      required:
        - favorite
    FavoriteDocumentItem:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        slug:
          type: string
          nullable: true
        folder_id:
          type: string
          nullable: true
        folder_path:
          type: string
          nullable: true
        updated_at:
          type: string
          nullable: true
        favorited_at:
          type: string
      required:
        - id
        - title
        - slug
        - folder_id
        - folder_path
        - updated_at
        - favorited_at
    RecentDocumentItem:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        slug:
          type: string
          nullable: true
        folder_id:
          type: string
          nullable: true
        folder_path:
          type: string
          nullable: true
        updated_at:
          type: string
          nullable: true
        last_opened_at:
          type: string
      required:
        - id
        - title
        - slug
        - folder_id
        - folder_path
        - updated_at
        - last_opened_at
    Folder:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        name:
          type: string
        parent_id:
          type: string
          nullable: true
        path:
          type: string
        level:
          type: number
        position:
          type: number
          nullable: true
        type:
          type: string
          nullable: true
        is_private:
          type: boolean
        owner_id:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
        - id
        - org_id
        - name
        - parent_id
        - path
        - level
        - is_private
        - created_at
        - updated_at
    FolderTreeNode:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        path:
          type: string
        level:
          type: number
        type:
          type: string
          enum:
            - folder
            - document
        is_private:
          type: boolean
          nullable: true
        owner_id:
          type: string
          nullable: true
        created_at:
          type: string
          nullable: true
        updated_at:
          type: string
          nullable: true
        file_size:
          type: number
          nullable: true
        mime_type:
          type: string
          nullable: true
        children:
          type: array
          items:
            type: object
            properties: {}
            additionalProperties:
              nullable: true
        documents:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              title:
                type: string
              folder_id:
                type: string
                nullable: true
              file_size:
                type: number
                nullable: true
              mime_type:
                type: string
                nullable: true
              created_at:
                type: string
                nullable: true
              updated_at:
                type: string
                nullable: true
            required:
              - id
              - title
              - folder_id
        stats:
          type: object
          properties:
            document_count:
              type: number
            total_size:
              type: number
            last_modified:
              type: string
          required:
            - document_count
            - total_size
            - last_modified
      required:
        - id
        - name
        - path
        - level
        - type
        - created_at
        - updated_at
    DecisionListItem:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        topic:
          type: string
        decision:
          type: string
        rationale:
          type: string
        category:
          type: string
          nullable: true
        severity:
          type: string
          nullable: true
        isolation_key:
          type: string
          nullable: true
        tags:
          type: array
          nullable: true
          items:
            type: string
        origin:
          type: string
        expires_when:
          type: string
          nullable: true
        confirmation_status:
          type: string
        condition_type:
          type: string
          nullable: true
        condition_metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        lifecycle_state:
          type: string
        sources:
          type: array
          items:
            $ref: "#/components/schemas/DecisionListSource"
        author:
          $ref: "#/components/schemas/DecisionAuthor"
        created_by:
          type: string
        created_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        updated_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        archived_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        seen_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
      required:
        - id
        - org_id
        - topic
        - decision
        - rationale
        - category
        - severity
        - tags
        - origin
        - expires_when
        - confirmation_status
        - condition_type
        - condition_metadata
        - lifecycle_state
        - sources
        - created_by
        - created_at
        - updated_at
        - archived_at
        - seen_at
    DecisionListSource:
      type: object
      properties:
        id:
          type: string
        source_type:
          type: string
        source_url:
          type: string
        extracted_at:
          type: string
          description: When the source edge was created, as Postgres timestamptz text; empty when it has no timestamp.
      required:
        - id
        - source_type
        - extracted_at
    DecisionAuthor:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
          nullable: true
        email:
          type: string
          nullable: true
    RecordedDecision:
      type: object
      properties:
        id:
          type: string
        topic:
          type: string
        decision:
          type: string
        rationale:
          type: string
        category:
          type: string
          nullable: true
        severity:
          type: string
          nullable: true
        tags:
          type: array
          nullable: true
          items:
            type: string
        expires_when:
          type: string
          nullable: true
        origin:
          type: string
        confirmation_status:
          type: string
        created_by:
          type: string
        author:
          allOf:
            - $ref: "#/components/schemas/DecisionAuthor"
            - nullable: true
        condition_type:
          type: string
          nullable: true
        lifecycle_state:
          type: string
        condition_metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        primitive_snapshot:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        proposal_context:
          type: string
          nullable: true
        assigned_to_email:
          type: string
          nullable: true
        isolation_key:
          type: string
          nullable: true
      required:
        - id
        - topic
        - decision
        - rationale
        - category
        - severity
        - tags
        - expires_when
        - origin
        - confirmation_status
        - created_by
        - author
        - condition_type
        - lifecycle_state
        - condition_metadata
        - primitive_snapshot
        - proposal_context
        - assigned_to_email
    Decision:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        topic:
          type: string
        decision:
          type: string
        rationale:
          type: string
        category:
          type: string
          nullable: true
        severity:
          type: string
          nullable: true
        isolation_key:
          type: string
          nullable: true
        tags:
          type: array
          nullable: true
          items:
            type: string
        origin:
          type: string
        expires_when:
          type: string
          nullable: true
        confirmation_status:
          type: string
        condition_type:
          type: string
          nullable: true
        condition_metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        lifecycle_state:
          type: string
        sources:
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/DecisionSource"
        author:
          allOf:
            - $ref: "#/components/schemas/DecisionAuthor"
            - nullable: true
        created_by:
          type: string
        created_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        updated_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        archived_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        primitive_snapshot:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        referenced_primitives:
          $ref: "#/components/schemas/ReferencedPrimitives"
        proposal_context:
          type: string
          nullable: true
        assigned_to_user_id:
          type: string
          nullable: true
        assigned_to_email:
          type: string
          nullable: true
        confirmed_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        rejected_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        rejection_reason:
          type: string
          nullable: true
        seen_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
      required:
        - id
        - org_id
        - topic
        - decision
        - rationale
        - category
        - severity
        - tags
        - origin
        - expires_when
        - confirmation_status
        - condition_type
        - condition_metadata
        - lifecycle_state
        - sources
        - author
        - created_by
        - created_at
        - updated_at
        - archived_at
        - primitive_snapshot
        - referenced_primitives
        - proposal_context
        - assigned_to_user_id
        - assigned_to_email
        - confirmed_at
        - rejected_at
        - rejection_reason
        - seen_at
    DecisionSource:
      type: object
      properties:
        type:
          type: string
        identifier:
          type: string
        url:
          type: string
        label:
          type: string
        source_type:
          type: string
        id:
          type: string
        extracted_at:
          type: string
          format: date-time
      required:
        - type
    ReferencedPrimitives:
      type: object
      nullable: true
      properties:
        research_signals:
          type: array
          items:
            type: string
        features:
          type: array
          items:
            type: string
        personas:
          type: array
          items:
            type: string
        strategy:
          type: boolean
        velocity:
          type: boolean
        market_position:
          type: boolean
    DecisionHistoryEntry:
      type: object
      properties:
        id:
          type: string
        decision_id:
          type: string
        previous_status:
          type: string
          nullable: true
        new_status:
          type: string
          nullable: true
        changed_by_user_id:
          type: string
          nullable: true
        changed_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        reason:
          type: string
          nullable: true
        snapshot:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        user_name:
          type: string
          nullable: true
        user_email:
          type: string
          nullable: true
      required:
        - id
        - decision_id
        - previous_status
        - new_status
        - changed_by_user_id
        - changed_at
        - reason
        - snapshot
        - user_name
        - user_email
    Feature:
      type: object
      properties:
        id:
          type: string
          format: uuid
        org_id:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        stage:
          type: string
          nullable: true
          enum:
            - planned
            - beta
            - ga
            - sunset
            - null
        confidence:
          type: number
          nullable: true
        visibility:
          type: string
          nullable: true
          enum:
            - public
            - internal
            - hidden
            - null
        priority:
          type: integer
          nullable: true
        user_edited:
          type: boolean
          nullable: true
        created_by:
          type: string
          nullable: true
        last_synced_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        source_url:
          type: string
          nullable: true
        first_available_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        ga_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        lifecycle_events:
          type: array
          items:
            $ref: "#/components/schemas/FeatureLifecycleEvent"
        created_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        updated_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
      required:
        - id
        - org_id
        - name
        - user_edited
        - created_by
        - last_synced_at
        - source_url
        - created_at
        - updated_at
    FeatureLifecycleEvent:
      type: object
      properties:
        stage:
          type: string
          enum:
            - beta
            - ga
            - sunset
        occurred_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        evidence_links:
          type: array
          items:
            type: string
            format: uri
            pattern: ^[hH][tT][tT][pP][sS]?:\/\/
          minItems: 1
        id:
          type: string
          format: uuid
        created_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
      required:
        - stage
        - occurred_at
        - evidence_links
        - id
        - created_at
    FeaturePersona:
      type: object
      properties:
        id:
          type: string
          format: uuid
        segment_name:
          type: string
        attribution_source:
          type: string
      required:
        - id
        - segment_name
        - attribution_source
    PendingFeatureSuggestion:
      type: object
      properties:
        id:
          type: string
          format: uuid
        org_id:
          type: string
          format: uuid
        feature_id:
          type: string
          nullable: true
          format: uuid
        suggested_name:
          type: string
        suggested_description:
          type: string
          nullable: true
        suggested_stage:
          type: string
          nullable: true
          enum:
            - beta
            - ga
            - planned
            - sunset
            - null
        evidence:
          type: object
          properties:
            work_items:
              type: array
              items:
                type: string
            doc_mentions:
              type: array
              items:
                type: string
            website_mentions:
              type: array
              items:
                type: string
            doc_source_urls:
              type: array
              items:
                type: string
                format: uri
            source_urls:
              type: array
              items:
                type: string
                format: uri
            source:
              type: string
            priority:
              type: string
              enum:
                - low
                - medium
                - high
                - critical
        confidence:
          type: number
        status:
          type: string
          enum:
            - pending
            - approved
            - rejected
        reviewed_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        reviewed_by:
          type: string
          nullable: true
        created_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        updated_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
      required:
        - id
        - org_id
        - feature_id
        - suggested_name
        - suggested_description
        - suggested_stage
        - evidence
        - confidence
        - status
        - reviewed_at
        - reviewed_by
        - created_at
        - updated_at
    CreateFeatureLifecycleEvent:
      type: object
      properties:
        stage:
          type: string
          enum:
            - beta
            - ga
            - sunset
        occurred_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp no later than the request time
        evidence_links:
          type: array
          items:
            type: string
            format: uri
            pattern: ^[hH][tT][tT][pP][sS]?:\/\/
          minItems: 1
      required:
        - stage
        - occurred_at
        - evidence_links
    Persona:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        segment_name:
          type: string
        description:
          type: string
          nullable: true
        priority:
          type: string
          enum:
            - high
            - medium
            - low
        segment_size:
          type: number
          nullable: true
        user_count:
          type: number
          nullable: true
        growth_rate:
          type: string
          nullable: true
        trend_data:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
              size:
                type: number
            required:
              - date
              - size
        needs:
          type: array
          items:
            type: string
        pain_points:
          type: array
          items:
            type: string
        quotes:
          type: array
          items:
            type: object
            properties:
              text:
                type: string
              date:
                type: string
              call_id:
                type: string
            required:
              - text
              - date
        session_frequency:
          type: string
          nullable: true
        feature_adoption:
          type: object
          additionalProperties:
            type: number
        power_user_count:
          type: number
        revenue_contribution:
          type: number
          nullable: true
        average_deal_size:
          type: number
          nullable: true
        churn_rate:
          type: number
          nullable: true
        confidence:
          type: number
        sources:
          type: array
          items:
            type: string
        first_detected:
          type: string
        last_updated:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        user_created:
          type: boolean
        user_edited:
          type: boolean
        last_edited_by:
          type: string
          nullable: true
        last_edited_at:
          type: string
          nullable: true
      required:
        - id
        - org_id
        - segment_name
        - priority
        - segment_size
        - user_count
        - growth_rate
        - trend_data
        - needs
        - pain_points
        - quotes
        - session_frequency
        - feature_adoption
        - power_user_count
        - revenue_contribution
        - average_deal_size
        - churn_rate
        - confidence
        - sources
        - first_detected
        - last_updated
        - created_at
        - updated_at
        - user_created
        - user_edited
        - last_edited_by
        - last_edited_at
    Conversation:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        created_by:
          type: string
        agent_name:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        context_folder_id:
          type: string
          nullable: true
        context_document_ids:
          type: array
          nullable: true
          items:
            type: string
        metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        model:
          type: string
          nullable: true
        model_name:
          type: string
          nullable: true
        model_provider:
          type: string
          nullable: true
        created_via_source:
          type: string
          nullable: true
        created_via_trigger:
          type: string
          nullable: true
        summary:
          type: string
          nullable: true
        summary_updated_at:
          type: string
          nullable: true
        summary_token_count:
          type: number
          nullable: true
        total_tokens:
          type: number
          nullable: true
        unsummarized_turn_count:
          type: number
          nullable: true
        model_context_window:
          type: number
          nullable: true
        compaction_in_progress:
          type: boolean
          nullable: true
        compaction_started_at:
          type: string
          nullable: true
        starred_at:
          type: string
          nullable: true
      required:
        - id
        - org_id
        - created_by
        - agent_name
        - title
        - context_folder_id
        - context_document_ids
        - metadata
        - created_at
        - updated_at
        - model
        - model_name
        - model_provider
        - created_via_source
        - created_via_trigger
        - summary
        - summary_updated_at
        - summary_token_count
        - total_tokens
        - unsummarized_turn_count
        - model_context_window
        - compaction_in_progress
        - compaction_started_at
        - starred_at
    Message:
      type: object
      properties:
        id:
          type: string
        conversation_id:
          type: string
        role:
          type: string
        content:
          type: string
        metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        created_at:
          type: string
        created_by:
          type: string
          nullable: true
        message_parts:
          nullable: true
        tool_invocations:
          nullable: true
        reasoning_steps:
          nullable: true
        ai_sdk_metadata:
          nullable: true
        estimated_tokens:
          type: number
          nullable: true
        is_summarized:
          type: boolean
          nullable: true
        summarized_at:
          type: string
          nullable: true
        ai_sdk_usage:
          nullable: true
        turn_id:
          type: string
          nullable: true
        finish_reason:
          type: string
          nullable: true
        participant_kind:
          type: string
          nullable: true
          enum:
            - human
            - agent
            - null
        participant_name:
          type: string
          nullable: true
        participant_harness:
          type: string
          nullable: true
        participant_worktree:
          type: string
          nullable: true
        participant_ticket:
          type: string
          nullable: true
      required:
        - id
        - conversation_id
        - role
        - content
        - metadata
        - created_at
        - created_by
        - estimated_tokens
        - is_summarized
        - summarized_at
        - turn_id
        - finish_reason
        - participant_kind
        - participant_name
        - participant_harness
        - participant_worktree
        - participant_ticket
    LiveReplayMessage:
      type: object
      properties:
        id:
          type: string
        role:
          type: string
          enum:
            - assistant
        created_at:
          type: string
        turn_id:
          type: string
          nullable: true
        content:
          type: string
        message_parts:
          type: array
          items:
            nullable: true
        metadata:
          type: object
          additionalProperties:
            nullable: true
      required:
        - id
        - role
        - created_at
        - turn_id
        - content
        - message_parts
        - metadata
    AgentRunStatus:
      type: object
      properties:
        runId:
          type: string
        agentName:
          type: string
        status:
          type: string
          enum:
            - queued
            - running
            - completed
            - failed
            - cancelled
        startedAt:
          type: string
        completedAt:
          type: string
          nullable: true
        result:
          nullable: true
        continuation_run_id:
          type: string
      required:
        - runId
        - agentName
        - status
        - startedAt
    SkillSummary:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
      required:
        - name
        - description
    SkillWriteResult:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        skill:
          type: object
          properties:
            id:
              type: string
            name:
              type: string
            title:
              type: string
            description:
              type: string
            source:
              type: string
            folderPath:
              type: string
            overlayId:
              type: string
            resolvedVersion:
              type: string
          required:
            - id
            - name
            - title
            - description
      required:
        - success
        - skill
    SkillArchiveResult:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        skill:
          type: object
          properties:
            id:
              type: string
            name:
              type: string
          required:
            - id
            - name
      required:
        - success
        - skill
    SkillImportResult:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        skill:
          type: object
          properties:
            title:
              type: string
            name:
              type: string
            description:
              type: string
            sourceUrl:
              type: string
              description: URL the skill was imported from
          required:
            - title
            - name
            - description
            - sourceUrl
      required:
        - success
        - skill
    BulkMoveResult:
      type: object
      properties:
        moved_documents:
          type: number
        moved_folders:
          type: number
        errors:
          type: array
          items:
            type: string
      required:
        - moved_documents
        - moved_folders
        - errors
    BulkDeleteResult:
      type: object
      properties:
        deleted_documents:
          type: number
          description: Total documents soft-deleted, including every document under a deleted folder's cascade
        deleted_folders:
          type: number
          description: Total folders soft-deleted, including every descendant of a requested folder, not just the requested roots
        errors:
          type: array
          items:
            type: string
      required:
        - deleted_documents
        - deleted_folders
        - errors
    ApiKey:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        name:
          type: string
          nullable: true
        prefix:
          type: string
        created_by:
          type: string
          nullable: true
        created_at:
          type: string
        last_used_at:
          type: string
          nullable: true
        revoked_at:
          type: string
          nullable: true
        user_id:
          type: string
          nullable: true
        scopes:
          type: array
          nullable: true
          items:
            type: string
      required:
        - id
        - org_id
        - name
        - prefix
        - created_by
        - created_at
        - last_used_at
        - revoked_at
        - user_id
        - scopes
    ApiKeyCreated:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
          nullable: true
        prefix:
          type: string
        created_at:
          type: string
        secret:
          type: string
      required:
        - id
        - name
        - prefix
        - created_at
        - secret
    ResearchSignalListItem:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        theme:
          type: string
        signal_type:
          type: string
          nullable: true
        source:
          type: string
        status:
          type: string
          enum:
            - new
            - reviewed
            - planned
            - shipped
            - dismissed
          description: Signal lifecycle status.
        touchpoints:
          type: number
          nullable: true
          description: Raw mention count.
        unique_customers:
          type: number
          description: "Breadth: distinct customers behind the mentions."
        customer_names:
          type: array
          items:
            type: string
        confidence:
          type: number
        metadata:
          nullable: true
        related_decisions:
          type: array
          items:
            type: string
        first_detected:
          type: string
        last_detected:
          type: string
        link_count:
          type: number
        created_at:
          type: string
          nullable: true
        updated_at:
          type: string
          nullable: true
        source_document_ids:
          type: array
          items:
            type: string
        persona_ids:
          type: array
          items:
            type: string
        derived_from_sources:
          type: array
          items:
            type: object
            properties:
              canonical_type:
                type: string
              external_id:
                type: string
                nullable: true
              entity_type:
                type: string
              entity_id:
                type: string
              entity_object_id:
                type: string
            required:
              - canonical_type
              - external_id
              - entity_type
              - entity_id
              - entity_object_id
      required:
        - id
        - org_id
        - theme
        - signal_type
        - source
        - status
        - touchpoints
        - unique_customers
        - customer_names
        - confidence
        - related_decisions
        - first_detected
        - last_detected
        - link_count
        - created_at
        - updated_at
        - source_document_ids
        - persona_ids
        - derived_from_sources
    ResearchSignal:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        theme:
          type: string
        signal_type:
          type: string
          nullable: true
        source:
          type: string
        frequency:
          type: number
          nullable: true
        confidence:
          type: number
          nullable: true
        metadata:
          nullable: true
        related_decisions:
          type: array
          nullable: true
          items:
            type: string
        last_detected:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        status:
          type: string
          enum:
            - new
            - reviewed
            - planned
            - shipped
            - dismissed
          description: Signal lifecycle status.
      required:
        - id
        - org_id
        - theme
        - source
        - created_at
        - updated_at
        - status
    WorkItem:
      type: object
      properties:
        title:
          type: string
        id:
          type: string
          format: uuid
        description:
          type: string
          nullable: true
        stage:
          type: string
        priority:
          type: number
          nullable: true
        source:
          type: string
        sources:
          type: array
          items:
            type: string
        source_details:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
              id:
                type: string
                nullable: true
              url:
                type: string
                nullable: true
            required:
              - type
        issue_id:
          type: string
        issue_url:
          type: string
        pr_id:
          type: string
        pr_url:
          type: string
        project_name:
          type: string
          nullable: true
        created_at:
          type: string
          nullable: true
        updated_at:
          type: string
          nullable: true
        completed_at:
          type: string
          nullable: true
      required:
        - title
        - stage
        - source
        - sources
        - source_details
        - created_at
        - updated_at
    EntityLink:
      type: object
      properties:
        id:
          type: string
        org_id:
          type: string
        source_type:
          type: string
        source_id:
          type: string
        target_type:
          type: string
        target_id:
          type: string
        relationship:
          type: string
        metadata:
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
        - id
        - org_id
        - source_type
        - source_id
        - target_type
        - target_id
        - relationship
        - created_at
        - updated_at
    ManualEntityLinkCreated:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        id:
          type: string
          description: The created (or reactivated) entity link id
        status:
          type: string
          enum:
            - confirmed
            - inferred
            - rejected
      required:
        - success
        - id
        - status
    ManualEntityLinkReactivated:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        id:
          type: string
        reactivated:
          type: boolean
          enum:
            - true
        status:
          type: string
          enum:
            - confirmed
            - inferred
            - rejected
      required:
        - success
        - id
        - reactivated
        - status
    EntityLinkConflict:
      type: object
      properties:
        error:
          type: string
        id:
          type: string
          description: The id of the existing (non-rejected) link
      required:
        - error
        - id
    EntityLinkRateLimited:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
          enum:
            - rate_limit_exceeded
        resolution_hint:
          type: string
        retry_after:
          type: number
          description: Seconds until the caller may retry
      required:
        - error
        - code
        - retry_after
    ManualEntityLinkCreateRequest:
      type: object
      properties:
        source_type:
          type: string
          enum:
            - research_signal
            - feature
            - work_item
            - persona
            - decision
            - document
        source_id:
          type: string
          description: Entity UUID. For source_type "decision", a "D-<n>" decision id is also accepted and resolved to its entity
            UUID.
        target_type:
          type: string
          enum:
            - research_signal
            - feature
            - work_item
            - persona
            - decision
            - document
        target_id:
          type: string
          description: Entity UUID. For target_type "decision", a "D-<n>" decision id is also accepted and resolved to its entity
            UUID.
        confidence:
          type: number
          minimum: 0
          maximum: 1
          default: 1
        match_method:
          type: string
          enum:
            - embedding
            - keyword
            - explicit
            - manual
          default: manual
        status:
          type: string
          enum:
            - confirmed
            - inferred
            - rejected
          default: confirmed
      required:
        - source_type
        - source_id
        - target_type
        - target_id
    EntityObject:
      type: object
      properties:
        id:
          type: string
          format: uuid
        canonical_type:
          type: string
        external_id:
          type: string
          nullable: true
        source_url:
          type: string
          nullable: true
        entity_type:
          type: string
        entity_id:
          type: string
          format: uuid
        title:
          type: string
          nullable: true
      required:
        - id
        - canonical_type
        - external_id
        - source_url
        - entity_type
        - entity_id
        - title
    ProductContextConfig:
      type: object
      properties:
        productAddress:
          type: string
          description: Public product URL used as the starting point for product research. Accepts an absolute http(s) URL or a
            scheme-less host and path (normalized to https); subdomains and paths are preserved, query and fragment are
            dropped. Send an empty string to clear it.
        company:
          type: object
          properties:
            website:
              type: string
              description: Deprecated alias for productAddress, kept for older clients. Same accepted forms and same normalization;
                used only when productAddress is absent from the request.
            customers:
              type: string
            service_definition:
              type: string
            competitive_advantages:
              type: array
              items:
                type: string
            businessModel:
              type: string
        goals:
          type: object
          properties:
            six_month_goal:
              type: string
        velocity:
          type: object
          properties:
            releaseFrequency:
              type: string
              enum:
                - daily
                - weekly
                - biweekly
                - monthly
                - quarterly
            decisionSpeed:
              type: number
              minimum: 1
              maximum: 10
            coordinationSpeed:
              type: number
              minimum: 1
              maximum: 10
            velocityPreference:
              type: number
              minimum: 1
              maximum: 10
          description: Desired ways of working; not observed delivery telemetry
        team:
          type: object
          properties:
            technicalSophistication:
              type: number
            qualityControl:
              type: number
            engineeringTeam:
              type: string
        metrics:
          type: object
          properties:
            topMetric1:
              type: string
            topMetric2:
              type: string
            topMetric3:
              type: string
    InferenceResultsDeleteBody:
      type: object
      properties:
        fields:
          type: array
          items:
            type: string
        reason:
          type: string
          enum:
            - duplicate
            - not_relevant
            - incorrect
            - merged
            - other
        note:
          type: string
        skipFeedback:
          type: boolean
    VelocityMetricsResponse:
      type: object
      properties:
        velocity:
          type: object
          nullable: true
          properties:
            releaseFrequency:
              type: string
              nullable: true
              description: Observed release cadence, e.g. daily/weekly
            avg_cycle_time_hours:
              type: number
              nullable: true
            throughput_issues_per_week:
              type: number
              nullable: true
            throughput_trend:
              type: string
              nullable: true
            last_measured:
              type: string
              nullable: true
            confidence:
              type: number
              nullable: true
            sources:
              type: array
              nullable: true
              items:
                type: string
          required:
            - releaseFrequency
            - avg_cycle_time_hours
            - throughput_issues_per_week
            - throughput_trend
            - last_measured
            - confidence
            - sources
          description: Computed velocity telemetry; null when no data yet
        updated_at:
          type: string
        message:
          type: string
          description: "Present when velocity is null: how to get data flowing"
      required:
        - velocity
    McpServer:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        endpoint:
          type: string
          format: uri
        auth_type:
          type: string
          enum:
            - api_key
            - bearer
            - basic
            - mtls
            - none
            - oauth
        auth_config:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        has_credentials:
          type: boolean
        timeout_ms:
          type: number
        max_retries:
          type: number
        enabled:
          type: boolean
        health_status:
          type: string
          nullable: true
        last_health_check:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        last_health_error:
          type: string
          nullable: true
        tool_count:
          type: number
          nullable: true
        manifest_cached_at:
          type: string
          nullable: true
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        rate_limit_per_minute:
          type: number
          nullable: true
        rate_limit_per_hour:
          type: number
          nullable: true
        managed_provider:
          type: string
          nullable: true
          description: Returned by the list and create endpoints only.
        oauth_status:
          type: string
          enum:
            - not_applicable
            - not_connected
            - connected
        oauth_client_id:
          type: string
          nullable: true
        oauth_issuer:
          type: string
          nullable: true
        oauth_dynamic_registration:
          type: boolean
        created_by:
          type: string
          nullable: true
        created_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
        updated_at:
          type: string
          description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
      required:
        - id
        - name
        - description
        - endpoint
        - auth_type
        - auth_config
        - has_credentials
        - timeout_ms
        - max_retries
        - enabled
        - health_status
        - last_health_check
        - last_health_error
        - tool_count
        - manifest_cached_at
        - rate_limit_per_minute
        - rate_limit_per_hour
        - oauth_status
        - oauth_client_id
        - oauth_issuer
        - oauth_dynamic_registration
        - created_by
        - created_at
        - updated_at
    MeResponse:
      type: object
      properties:
        id:
          type: string
          description: Clerk user ID
        firstName:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 user creation timestamp
        lastSeenAt:
          type: string
          nullable: true
          format: date-time
          description: Last-seen ISO timestamp from Clerk unsafeMetadata
      required:
        - id
        - firstName
        - createdAt
        - lastSeenAt
    PatchMeResponse:
      type: object
      properties:
        ok:
          type: boolean
          enum:
            - true
      required:
        - ok
    PatchMeBody:
      type: object
      properties:
        lastSeenAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp to record
      required:
        - lastSeenAt
    ChatTurnState:
      type: object
      properties:
        version:
          type: number
          enum:
            - 1
        chatTurnId:
          type: string
        conversationId:
          type: string
        messageTurnId:
          type: string
        status:
          type: string
          enum:
            - queued
            - running
            - waiting
            - finalizing
            - succeeded
            - failed
            - cancelled
        reason:
          type: string
        recovery:
          type: string
          enum:
            - observe
            - resume
            - none
        retryAfterMs:
          type: number
      required:
        - version
        - chatTurnId
        - conversationId
        - messageTurnId
        - status
        - recovery
    Competitor:
      type: object
      properties:
        id:
          type: string
        orgId:
          type: string
        name:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        website:
          type: string
          nullable: true
        domain:
          type: string
          nullable: true
        status:
          type: string
        metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
        lastCrawlAt:
          type: string
          nullable: true
        crawlContent:
          nullable: true
        crawlStatus:
          type: string
          nullable: true
        positioning:
          type: string
          nullable: true
        keyFeatures:
          nullable: true
        pricingModel:
          type: string
          nullable: true
        targetAudience:
          type: string
          nullable: true
        messagingSummary:
          type: string
          nullable: true
        tagline:
          type: string
          nullable: true
        previousCrawlContent:
          nullable: true
        lastDiffAt:
          type: string
          nullable: true
        lastProfileSnapshot:
          nullable: true
        createdAt:
          type: string
          nullable: true
        updatedAt:
          type: string
          nullable: true
        seenAt:
          type: string
          nullable: true
      required:
        - id
        - orgId
        - name
        - description
        - website
        - domain
        - status
        - metadata
        - lastCrawlAt
        - crawlStatus
        - positioning
        - pricingModel
        - targetAudience
        - messagingSummary
        - tagline
        - lastDiffAt
        - createdAt
        - updatedAt
        - seenAt
    Deal:
      type: object
      properties:
        id:
          type: string
        externalId:
          type: string
        name:
          type: string
        accountName:
          type: string
          nullable: true
        dealName:
          type: string
        stage:
          type: string
        lifecycleStatus:
          type: string
        value:
          type: number
          nullable: true
        currency:
          type: string
        owner:
          type: string
          nullable: true
        closeDate:
          type: string
          nullable: true
        source:
          type: string
        sourceUrl:
          type: string
          nullable: true
        accountEmail:
          type: string
          nullable: true
        accountDomain:
          type: string
          nullable: true
        accountPhone:
          type: string
          nullable: true
        closeReason:
          type: string
          nullable: true
        updatedAt:
          type: string
          nullable: true
      required:
        - id
        - externalId
        - name
        - accountName
        - dealName
        - stage
        - lifecycleStatus
        - value
        - currency
        - owner
        - closeDate
        - source
        - sourceUrl
        - accountEmail
        - accountDomain
        - accountPhone
        - closeReason
        - updatedAt
  parameters: {}
paths:
  /api/v1/health:
    get:
      summary: Health check
      description: Returns service health status and caller identity.
      security:
        - ApiKeyAuth: []
      responses:
        "200":
          description: Service is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  orgId:
                    type: string
                  via:
                    type: string
                  client:
                    type: string
                required:
                  - ok
                  - orgId
                  - via
                  - client
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents:
    get:
      tags:
        - Documents
      summary: List documents
      security: &a1
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            minLength: 1
          required: false
          name: folder_id
          in: query
        - schema:
            type: integer
            minimum: 1
            default: 1
            description: Legacy offset page; follow next_cursor for stable traversal
          required: false
          description: Legacy offset page; follow next_cursor for stable traversal
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            description: Opaque next_cursor from the previous response
          required: false
          description: Opaque next_cursor from the previous response
          name: cursor
          in: query
      responses:
        "200":
          description: Paginated document list
          content:
            application/json:
              schema:
                type: object
                properties:
                  documents:
                    type: array
                    items:
                      $ref: "#/components/schemas/DocumentListItem"
                  pagination:
                    $ref: "#/components/schemas/CursorPagination"
                required:
                  - documents
                  - pagination
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Documents
      summary: Create document
      security: *a1
      requestBody:
        description: Document to create
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                content:
                  nullable: true
                folder_id:
                  type: string
                  minLength: 1
                category:
                  type: string
              required:
                - folder_id
      responses:
        "201":
          description: Document created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  title:
                    type: string
                  folder_id:
                    type: string
                    nullable: true
                  folder_path:
                    type: string
                    nullable: true
                  category:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                  updated_at:
                    type: string
                required:
                  - id
                  - title
                  - folder_id
                  - created_at
                  - updated_at
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}:
    get:
      tags:
        - Documents
      summary: Get document
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Full document object
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Document"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Documents
      summary: Update document
      description: Update fields directly, apply a text edit, or append content. Only supplied fields are changed.
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                content:
                  nullable: true
                plaintext:
                  type: string
                  maxLength: 2000000
                markdown:
                  type: string
                  maxLength: 2000000
                edit:
                  type: object
                  properties:
                    old_text:
                      type: string
                      minLength: 1
                    new_text:
                      type: string
                      maxLength: 2000000
                    replace_all:
                      type: boolean
                  required:
                    - old_text
                    - new_text
                append:
                  type: string
                  maxLength: 2000000
                folder_id:
                  type: string
                  nullable: true
                  minLength: 1
                base_revision:
                  type: integer
                  minimum: 0
      responses:
        "200":
          description: Document updated. For edit operations, includes edit_result with status 'applied' or 'already_applied'.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdated"
        "400":
          description: Bad request. For edit operations, may include fuzzy match suggestion.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
        "409":
          description: Stale base_revision, or metadata bundled with an active-room body edit. Apply the body edit first, then
            update metadata separately.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StaleWriteConflict"
        "422":
          description: Live edit could not be applied; may include edit_result with a fuzzy match suggestion.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
        "425":
          description: The active live editor room prevents this canonical write.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error. An uncertain append requires reading the document before retrying.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
        "503":
          description: Live editor unavailable, or the applied edit's response could not be completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
        "504":
          description: Live edit checkpoint could not be confirmed. Read the document before retrying an append.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUpdateError"
    delete:
      tags:
        - Documents
      summary: Delete document (trash)
      description: Soft-deletes a document by moving it to the trash.
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Document trashed
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                required:
                  - success
                  - message
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/move:
    post:
      tags:
        - Documents
      summary: Move document to folder
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      requestBody:
        description: Target folder
        content:
          application/json:
            schema:
              type: object
              properties:
                folder_id:
                  type: string
                  nullable: true
                  minLength: 1
              required:
                - folder_id
      responses:
        "200":
          description: Document moved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentMoved"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/permanent:
    delete:
      tags:
        - Documents
      summary: Permanently delete document
      description: Irreversibly deletes a document. Cannot be undone.
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Document permanently deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                required:
                  - success
                  - message
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/restore:
    post:
      tags:
        - Documents
      summary: Restore document from trash
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Document restored
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                required:
                  - success
                  - message
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/url:
    get:
      tags:
        - Documents
      summary: Get signed download URL
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Signed URL
          content:
            application/json:
              schema:
                type: object
                properties:
                  url:
                    type: string
                required:
                  - url
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/extract:
    post:
      tags:
        - Documents
      summary: Extract content from file
      description: Triggers content extraction (OCR / text extraction) for an uploaded file.
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Extraction started
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/versions:
    get:
      tags:
        - Documents
      summary: List document versions
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
        - schema:
            type: number
            nullable: true
          required: false
          name: limit
          in: query
        - schema:
            type: number
            nullable: true
          required: false
          name: offset
          in: query
      responses:
        "200":
          description: Version list
          content:
            application/json:
              schema:
                type: object
                properties:
                  versions:
                    type: array
                    items:
                      $ref: "#/components/schemas/VersionSummary"
                  total:
                    type: number
                  limit:
                    type: number
                  offset:
                    type: number
                required:
                  - versions
                  - total
                  - limit
                  - offset
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Documents
      summary: Create version snapshot
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "201":
          description: Version created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                  version:
                    type: object
                    nullable: true
                    properties:
                      id:
                        type: string
                      trigger:
                        type: string
                      created_at:
                        type: string
                    required:
                      - id
                      - trigger
                      - created_at
                required:
                  - success
                  - message
                  - version
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/versions/{versionId}:
    get:
      tags:
        - Documents
      summary: Get document version
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
        - schema:
            type: string
            description: Version ID
          required: true
          description: Version ID
          name: versionId
          in: path
      responses:
        "200":
          description: Version details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VersionSummary"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/versions/{versionId}/restore:
    post:
      tags:
        - Documents
      summary: Restore document version
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
        - schema:
            type: string
            description: Version ID
          required: true
          description: Version ID
          name: versionId
          in: path
      responses:
        "200":
          description: Version restored
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                required:
                  - success
                  - message
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/upload:
    post:
      tags:
        - Documents
      summary: Upload file
      description: Upload a file as a new document via multipart/form-data.
      security: *a1
      requestBody:
        description: Multipart form with file, folder_id, and optional category
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                folder_id:
                  type: string
                category:
                  type: string
              required:
                - file
                - folder_id
      responses:
        "201":
          description: Uploaded document
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentCreated"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/trash:
    get:
      tags:
        - Documents
      summary: List trashed documents
      security: *a1
      parameters:
        - schema:
            type: integer
            minimum: 1
            default: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
          required: false
          name: limit
          in: query
      responses:
        "200":
          description: Trashed documents
          content:
            application/json:
              schema:
                type: object
                properties:
                  documents:
                    type: array
                    items:
                      $ref: "#/components/schemas/DocumentListItem"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
                required:
                  - documents
                  - pagination
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Documents
      summary: Empty trash
      description: Permanently deletes all trashed documents for the organization.
      security: *a1
      responses:
        "200":
          description: Trash emptied
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                  count:
                    type: number
                required:
                  - success
                  - message
                  - count
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/comments:
    get:
      tags:
        - Documents
      summary: List document comments
      description: All live comments on the document (flat array; replies reference their thread root via parent_comment_id).
        Requires any role on the document.
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Comment list
          content:
            application/json:
              schema:
                type: object
                properties:
                  comments:
                    type: array
                    items:
                      $ref: "#/components/schemas/DocumentComment"
                required:
                  - comments
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Documents
      summary: Create comment
      description: Create a root comment (optionally anchored to a text quote) or a reply (parent_comment_id must be a live
        thread root). Requires write capability and the authenticated user's folder access. Mentions use
        @[Name](mention:userId) tokens in the body. Source/client come from the auth context. External agent names are
        self-reported; web sessions always create human comments.
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
        - schema:
            type: string
            pattern: ^\s*(?:\S|\S[\s\S]{0,198}\S)\s*$
            description: Self-reported agent identity for API-key, OAuth, or authenticated MCP forwarding; ignored for web sessions.
              The server trims whitespace, then requires 1-200 characters. Omitted for human comments.
          required: false
          description: Self-reported agent identity for API-key, OAuth, or authenticated MCP forwarding; ignored for web sessions.
            The server trims whitespace, then requires 1-200 characters. Omitted for human comments.
          name: X-Brief-Comment-Agent
          in: header
      requestBody:
        description: Comment to create
        content:
          application/json:
            schema:
              type: object
              properties:
                body:
                  type: string
                  minLength: 1
                  maxLength: 10000
                quote:
                  type: object
                  nullable: true
                  properties:
                    text:
                      type: string
                      minLength: 1
                      maxLength: 2000
                    prefix:
                      type: string
                      maxLength: 200
                    suffix:
                      type: string
                      maxLength: 200
                  required:
                    - text
                parent_comment_id:
                  type: string
                  format: uuid
              required:
                - body
      responses:
        "201":
          description: Comment created
          content:
            application/json:
              schema:
                type: object
                properties:
                  comment:
                    $ref: "#/components/schemas/DocumentComment"
                required:
                  - comment
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/comments/{commentId}:
    patch:
      tags:
        - Documents
      summary: Update comment
      description: Edit a non-agent comment's body (author only; mentions re-parsed). Agent comment bodies cannot be edited.
        Resolve/reopen any thread root (status transitions are root-only — replies 400).
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
        - schema:
            type: string
            description: Comment ID
          required: true
          description: Comment ID
          name: commentId
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                body:
                  type: string
                  minLength: 1
                  maxLength: 10000
                status:
                  type: string
                  enum:
                    - open
                    - resolved
      responses:
        "200":
          description: Updated comment
          content:
            application/json:
              schema:
                type: object
                properties:
                  comment:
                    $ref: "#/components/schemas/DocumentComment"
                required:
                  - comment
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Documents
      summary: Delete comment
      description: Soft-delete a comment (author, or an editor on the document).
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
        - schema:
            type: string
            description: Comment ID
          required: true
          description: Comment ID
          name: commentId
          in: path
      responses:
        "200":
          description: Comment deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/presence:
    post:
      tags:
        - Documents
      summary: Presence heartbeat
      description: "Record the caller in the document's ephemeral presence roster and return the live roster (includes the
        caller). Best-effort: infra hiccups return an empty roster rather than an error. docId/userId must match the
        URL/authenticated caller."
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      requestBody:
        description: Heartbeat
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DocumentPresenceHeartbeat"
      responses:
        "200":
          description: Live roster
          content:
            application/json:
              schema:
                type: object
                properties:
                  viewers:
                    type: array
                    items:
                      $ref: "#/components/schemas/DocumentPresenceEntry"
                required:
                  - viewers
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Documents
      summary: Presence leave
      description: Remove the caller from the document's presence roster (fired on tab close/unmount).
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Left the roster
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                required:
                  - ok
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/open:
    post:
      tags:
        - Documents
      summary: Record document open
      description: Record that the caller opened the document (feeds the per-user recents list). Read access required.
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      responses:
        "200":
          description: Open recorded
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/{id}/favorite:
    post:
      tags:
        - Documents
      summary: Set or clear favorite
      description: Set or clear the caller's favorite flag on the document (personal annotation; read access required).
      security: *a1
      parameters:
        - schema:
            type: string
            description: Document ID
          required: true
          description: Document ID
          name: id
          in: path
      requestBody:
        description: Favorite flag
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FavoriteBody"
      responses:
        "200":
          description: Favorite updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  favorite:
                    type: boolean
                required:
                  - success
                  - favorite
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/me/documents/favorites:
    get:
      tags:
        - Documents
      summary: List my favorite documents
      description: The caller's favorited documents, ACL-intersected — a doc whose folder access (or explicit grant) has been
        revoked silently drops out.
      security: *a1
      parameters:
        - schema:
            type: number
            nullable: true
            description: 1-100, default 50
          required: false
          description: 1-100, default 50
          name: limit
          in: query
      responses:
        "200":
          description: Favorite documents
          content:
            application/json:
              schema:
                type: object
                properties:
                  documents:
                    type: array
                    items:
                      $ref: "#/components/schemas/FavoriteDocumentItem"
                required:
                  - documents
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/me/documents/recents:
    get:
      tags:
        - Documents
      summary: List my recently opened documents
      description: The caller's recently opened documents (most recent first), ACL-intersected like favorites.
      security: *a1
      parameters:
        - schema:
            type: number
            nullable: true
            description: 1-50, default 20
          required: false
          description: 1-50, default 20
          name: limit
          in: query
      responses:
        "200":
          description: Recent documents
          content:
            application/json:
              schema:
                type: object
                properties:
                  documents:
                    type: array
                    items:
                      $ref: "#/components/schemas/RecentDocumentItem"
                required:
                  - documents
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/documents/import:
    post:
      tags:
        - Documents
      summary: Import documents in a batch
      description: Queues up to 100 documents for import into a folder. Poll `GET /api/v1/jobs/{jobId}` for progress.
      security: *a1
      requestBody:
        description: Documents to import
        content:
          application/json:
            schema:
              type: object
              properties:
                documents:
                  type: array
                  items:
                    type: object
                    properties:
                      title:
                        type: string
                        minLength: 1
                        maxLength: 500
                      content:
                        type: string
                      category:
                        type: string
                    required:
                      - title
                      - content
                  minItems: 1
                  maxItems: 100
                folder_id:
                  type: string
                  format: uuid
                options:
                  type: object
                  properties:
                    skip_duplicates:
                      type: boolean
              required:
                - documents
                - folder_id
      responses:
        "202":
          description: Import job queued
          content:
            application/json:
              schema:
                type: object
                properties:
                  job_id:
                    type: string
                  status:
                    type: string
                    enum:
                      - pending
                  total_count:
                    type: integer
                  message:
                    type: string
                required:
                  - job_id
                  - status
                  - total_count
                  - message
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/jobs/{jobId}:
    get:
      tags:
        - Documents
      summary: Get the status of an import job
      security: *a1
      parameters:
        - schema:
            type: string
            format: uuid
            description: Import job ID
          required: true
          description: Import job ID
          name: jobId
          in: path
      responses:
        "200":
          description: Import job
          content:
            application/json:
              schema:
                type: object
                properties:
                  job_id:
                    type: string
                  status:
                    type: string
                    enum:
                      - pending
                      - processing
                      - completed
                      - failed
                  total_count:
                    type: integer
                  processed_count:
                    type: integer
                  success_count:
                    type: integer
                  error_count:
                    type: integer
                  folder_id:
                    type: string
                    nullable: true
                  errors:
                    type: array
                    items:
                      type: object
                      properties:
                        index:
                          type: integer
                        title:
                          type: string
                        error:
                          type: string
                      required:
                        - index
                        - title
                        - error
                  created_document_ids:
                    type: array
                    items:
                      type: string
                  created_at:
                    type: string
                  updated_at:
                    type: string
                  completed_at:
                    type: string
                    nullable: true
                required:
                  - job_id
                  - status
                  - total_count
                  - processed_count
                  - success_count
                  - error_count
                  - folder_id
                  - errors
                  - created_document_ids
                  - created_at
                  - updated_at
                  - completed_at
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/folders:
    get:
      tags:
        - Folders
      summary: List folders
      security: &a2
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: boolean
            nullable: true
            default: false
          required: false
          name: include_documents
          in: query
        - schema:
            type: boolean
            nullable: true
            default: true
          required: false
          name: include_stats
          in: query
        - schema:
            type: boolean
            nullable: true
            default: false
          required: false
          name: flat
          in: query
      responses:
        "200":
          description: Folder list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Folder"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Folders
      summary: Create folder
      security: *a2
      requestBody:
        description: Folder to create
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                parent_id:
                  type: string
                  format: uuid
              required:
                - name
                - parent_id
      responses:
        "201":
          description: Folder created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Folder"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/folders/{id}:
    get:
      tags:
        - Folders
      summary: Get folder
      security: *a2
      parameters:
        - schema:
            type: string
            description: Folder ID
          required: true
          description: Folder ID
          name: id
          in: path
      responses:
        "200":
          description: Folder details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Folder"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Folders
      summary: Update folder
      security: *a2
      parameters:
        - schema:
            type: string
            description: Folder ID
          required: true
          description: Folder ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                parent_id:
                  type: string
                  nullable: true
                  minLength: 1
                is_private:
                  type: boolean
      responses:
        "200":
          description: Folder updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Folder"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Folders
      summary: Delete folder
      security: *a2
      parameters:
        - schema:
            type: string
            description: Folder ID
          required: true
          description: Folder ID
          name: id
          in: path
      responses:
        "200":
          description: Folder deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/folders/{id}/move:
    patch:
      tags:
        - Folders
      summary: Move folder
      security: *a2
      parameters:
        - schema:
            type: string
            description: Folder ID
          required: true
          description: Folder ID
          name: id
          in: path
      requestBody:
        description: Target parent folder
        content:
          application/json:
            schema:
              type: object
              properties:
                parent_id:
                  type: string
                  minLength: 1
              required:
                - parent_id
      responses:
        "200":
          description: Folder moved
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                  operation:
                    type: string
                    enum:
                      - folder.move
                  folder:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      parent_id:
                        type: string
                      path:
                        type: string
                      level:
                        type: number
                    required:
                      - id
                      - name
                      - parent_id
                      - path
                      - level
                required:
                  - success
                  - message
                  - operation
                  - folder
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/folders/{id}/delete:
    delete:
      tags:
        - Folders
      summary: Delete folder (alternative)
      deprecated: true
      security: *a2
      parameters:
        - schema:
            type: string
            description: Folder ID
          required: true
          description: Folder ID
          name: id
          in: path
      responses:
        "200":
          description: Folder deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/folders/{id}/documents:
    get:
      tags:
        - Folders
      summary: List folder documents
      security: *a2
      parameters:
        - schema:
            type: string
            description: Folder ID
          required: true
          description: Folder ID
          name: id
          in: path
        - schema:
            type: number
            minimum: 1
            default: 1
            description: Legacy offset page; follow next_cursor for stable traversal
          required: false
          description: Legacy offset page; follow next_cursor for stable traversal
          name: page
          in: query
        - schema:
            type: number
            minimum: 1
            maximum: 500
            default: 200
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            description: Opaque next_cursor from the previous response
          required: false
          description: Opaque next_cursor from the previous response
          name: cursor
          in: query
        - schema:
            type: boolean
            nullable: true
            default: false
          required: false
          name: include_total
          in: query
      responses:
        "200":
          description: Folder contents
          content:
            application/json:
              schema:
                type: object
                properties:
                  folder:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                    required:
                      - id
                      - name
                  documents:
                    type: array
                    items:
                      nullable: true
                  subfolders:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        type:
                          type: string
                          nullable: true
                        is_private:
                          type: boolean
                        owner_id:
                          type: string
                          nullable: true
                        updated_at:
                          type: string
                          nullable: true
                      required:
                        - id
                        - name
                        - is_private
                  pagination:
                    type: object
                    properties:
                      page:
                        type: number
                      limit:
                        type: number
                      hasMore:
                        type: boolean
                      next_cursor:
                        type: string
                        nullable: true
                    required:
                      - page
                      - limit
                      - hasMore
                      - next_cursor
                required:
                  - folder
                  - documents
                  - subfolders
                  - pagination
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Folders
      summary: Move documents into folder
      security: *a2
      parameters:
        - schema:
            type: string
            description: Folder ID
          required: true
          description: Folder ID
          name: id
          in: path
      requestBody:
        description: Document IDs to move
        content:
          application/json:
            schema:
              type: object
              properties:
                documentIds:
                  type: array
                  items:
                    type: string
                    format: uuid
                  minItems: 1
                  maxItems: 100
              required:
                - documentIds
      responses:
        "200":
          description: Documents moved
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  moved_count:
                    type: number
                  target_folder:
                    type: object
                    properties:
                      id:
                        type: string
                      path:
                        type: string
                    required:
                      - id
                      - path
                required:
                  - success
                  - moved_count
                  - target_folder
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/folders/tree:
    get:
      tags:
        - Folders
      summary: Get folder tree
      description: Returns a hierarchical folder tree starting from the given path.
      security: *a2
      parameters:
        - schema:
            type: string
            default: /
          required: false
          name: path
          in: query
        - schema:
            type: number
            minimum: 1
            maximum: 5
            default: 1
          required: false
          name: depth
          in: query
        - schema:
            type: boolean
            nullable: true
            default: true
          required: false
          name: include_documents
          in: query
        - schema:
            type: boolean
            nullable: true
            default: true
          required: false
          name: include_stats
          in: query
      responses:
        "200":
          description: Folder tree
          content:
            application/json:
              schema:
                type: object
                properties:
                  tree:
                    type: array
                    items:
                      $ref: "#/components/schemas/FolderTreeNode"
                  path:
                    type: string
                  depth_requested:
                    type: number
                  depth_actual:
                    type: number
                  permissions:
                    type: string
                required:
                  - tree
                  - path
                  - depth_requested
                  - depth_actual
                  - permissions
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/folders/my-documents:
    get:
      tags:
        - Folders
      summary: Get personal documents folder
      description: Returns the current user's personal documents folder.
      security: *a2
      responses:
        "200":
          description: Personal folder
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                required:
                  - id
                  - name
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions:
    get:
      summary: List decisions
      tags:
        - Decisions
      security: &a3
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: boolean
          required: false
          name: include_archived
          in: query
        - schema:
            type: string
            description: Comma-separated tag filter
          required: false
          description: Comma-separated tag filter
          name: tags
          in: query
        - schema:
            type: string
            description: Comma-separated tags (all must match)
          required: false
          description: Comma-separated tags (all must match)
          name: tags_all
          in: query
        - schema:
            type: string
            description: Comma-separated categories
          required: false
          description: Comma-separated categories
          name: category
          in: query
        - schema:
            type: string
            description: Comma-separated severities
          required: false
          description: Comma-separated severities
          name: severity
          in: query
        - schema:
            type: string
            description: Comma-separated lifecycle states
          required: false
          description: Comma-separated lifecycle states
          name: lifecycle_state
          in: query
        - schema:
            type: string
            description: Comma-separated condition types
          required: false
          description: Comma-separated condition types
          name: condition_type
          in: query
        - schema:
            type: string
            enum:
              - proposed
              - confirmed
              - rejected
          required: false
          name: confirmation_status
          in: query
        - schema:
            type: boolean
          required: false
          name: assigned_to_me
          in: query
        - schema:
            type: boolean
          required: false
          name: created_by_me
          in: query
        - schema:
            type: string
          required: false
          name: query
          in: query
        - schema:
            type: string
            description: Isolation-key filter. Omit for legacy/no-filter behaviour, empty string for org-wide only, string for
              org-wide + matching `isolation_key`.
          required: false
          description: Isolation-key filter. Omit for legacy/no-filter behaviour, empty string for org-wide only, string for
            org-wide + matching `isolation_key`.
          name: isolation_key
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
          required: false
          name: limit
          in: query
        - schema:
            type: integer
            minimum: 0
            default: 0
          required: false
          name: offset
          in: query
      responses:
        "200":
          description: List of decisions
          content:
            application/json:
              schema:
                type: object
                properties:
                  decisions:
                    type: array
                    items:
                      $ref: "#/components/schemas/DecisionListItem"
                  related_decisions:
                    type: array
                    items:
                      type: object
                      properties:
                        decision:
                          type: object
                          properties:
                            id:
                              type: string
                            topic:
                              type: string
                              nullable: true
                            decision:
                              type: string
                              nullable: true
                            rationale:
                              type: string
                              nullable: true
                            category:
                              type: string
                              nullable: true
                            severity:
                              type: string
                              nullable: true
                            lifecycle_state:
                              type: string
                              nullable: true
                          required:
                            - id
                            - topic
                            - decision
                            - rationale
                            - category
                            - severity
                        via:
                          type: array
                          items:
                            type: object
                            properties:
                              entity_type:
                                type: string
                              entity_id:
                                type: string
                              title:
                                type: string
                                nullable: true
                              degree:
                                type: number
                            required:
                              - entity_type
                              - entity_id
                              - title
                              - degree
                        confidence:
                          type: string
                          enum:
                            - high
                            - medium
                      required:
                        - decision
                        - via
                        - confidence
                  total:
                    type: number
                  limit:
                    type: number
                  offset:
                    type: number
                  has_more:
                    type: boolean
                required:
                  - decisions
                  - total
                  - limit
                  - offset
                  - has_more
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/record:
    post:
      summary: Record a decision
      tags:
        - Decisions
      security: *a3
      requestBody:
        description: Decision to record
        content:
          application/json:
            schema:
              type: object
              properties:
                decision:
                  type: string
                rationale:
                  type: string
                topic:
                  type: string
                category:
                  type: string
                severity:
                  type: string
                origin:
                  type: string
                tags:
                  type: array
                  items:
                    nullable: true
                expires_when:
                  type: string
                  nullable: true
                sources:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                      identifier:
                        type: string
                      url:
                        type: string
                      label:
                        type: string
                      source_type:
                        type: string
                      id:
                        type: string
                      extracted_at:
                        type: string
                    additionalProperties:
                      nullable: true
                supersedes:
                  type: array
                  items:
                    type: string
                condition_type:
                  type: string
                condition_metadata:
                  type: object
                  additionalProperties:
                    nullable: true
                lifecycle_state:
                  type: string
                author:
                  type: object
                  properties:
                    id:
                      type: string
                    name:
                      type: string
                    email:
                      type: string
                proposal_context:
                  type: string
                assigned_to_email:
                  type: string
                send_invite:
                  type: boolean
                confirmation_status:
                  type: string
                isolation_key:
                  type: string
                  nullable: true
              additionalProperties:
                nullable: true
      responses:
        "200":
          description: Duplicate decision found
          content:
            application/json:
              schema:
                type: object
                properties:
                  record:
                    $ref: "#/components/schemas/RecordedDecision"
                  deduplicated:
                    type: boolean
                    enum:
                      - true
                  existing_id:
                    type: string
                  requiresConfirmation:
                    type: boolean
                  invite_sent:
                    type: boolean
                required:
                  - record
                  - deduplicated
                  - existing_id
                  - requiresConfirmation
                  - invite_sent
        "201":
          description: Decision recorded
          content:
            application/json:
              schema:
                type: object
                properties:
                  record:
                    $ref: "#/components/schemas/RecordedDecision"
                  deduplicated:
                    type: boolean
                  requiresConfirmation:
                    type: boolean
                  invite_sent:
                    type: boolean
                required:
                  - record
                  - deduplicated
                  - requiresConfirmation
                  - invite_sent
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/{id}:
    get:
      summary: Get decision by ID
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
        - schema:
            type: string
            description: Include an isolated decision when its scope matches this key
          required: false
          description: Include an isolated decision when its scope matches this key
          name: isolation_key
          in: query
      responses:
        "200":
          description: Decision details
          content:
            application/json:
              schema:
                type: object
                properties:
                  decision:
                    $ref: "#/components/schemas/Decision"
                required:
                  - decision
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      summary: Update decision
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                proposal_context:
                  type: string
                decision:
                  type: string
                rationale:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
                expires_when:
                  type: string
                  nullable: true
                topic:
                  type: string
                isolation_key:
                  type: string
                  nullable: true
      responses:
        "200":
          description: Updated decision
          content:
            application/json:
              schema:
                type: object
                properties:
                  decision:
                    $ref: "#/components/schemas/Decision"
                required:
                  - decision
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      summary: Delete decision
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      responses:
        "200":
          description: Deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/{id}/confirm:
    post:
      summary: Confirm a decision
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      requestBody:
        description: Optional overrides when confirming
        content:
          application/json:
            schema:
              type: object
              properties:
                decision:
                  type: string
                  minLength: 1
                rationale:
                  type: string
                  minLength: 1
                tags:
                  type: array
                  items:
                    type: string
                expires_when:
                  type: string
                  nullable: true
      responses:
        "200":
          description: Decision confirmed
          content:
            application/json:
              schema:
                type: object
                properties:
                  decision:
                    type: object
                    properties:
                      id:
                        type: string
                      confirmation_status:
                        type: string
                      confirmed_at:
                        type: string
                        description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
                    required:
                      - id
                      - confirmation_status
                      - confirmed_at
                required:
                  - decision
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/{id}/reject:
    post:
      summary: Reject a decision
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      requestBody:
        description: Rejection reason (required)
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  minLength: 1
              required:
                - reason
      responses:
        "200":
          description: Decision rejected
          content:
            application/json:
              schema:
                type: object
                properties:
                  decision:
                    type: object
                    properties:
                      id:
                        type: string
                      confirmation_status:
                        type: string
                      rejected_at:
                        type: string
                        description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
                      rejection_reason:
                        type: string
                    required:
                      - id
                      - confirmation_status
                      - rejected_at
                      - rejection_reason
                required:
                  - decision
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/{id}/archive:
    post:
      summary: Archive decision
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      requestBody:
        description: Optional archive reason
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
      responses:
        "200":
          description: Decision archived
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  decision:
                    type: object
                    properties:
                      id:
                        type: string
                      topic:
                        type: string
                        nullable: true
                      decision:
                        type: string
                        nullable: true
                      archived_at:
                        type: string
                        description: 'Postgres timestamptz text, for example "2026-10-08 12:00:00.123456+00". Not RFC 3339: parse it as a date.'
                    required:
                      - id
                      - topic
                      - decision
                      - archived_at
                  message:
                    type: string
                  reason:
                    type: string
                  operation:
                    type: string
                    enum:
                      - decision.archive
                required:
                  - success
                  - decision
                  - message
                  - operation
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      summary: Restore archived decision
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      responses:
        "200":
          description: Decision restored
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  decision:
                    type: object
                    properties:
                      id:
                        type: string
                      topic:
                        type: string
                        nullable: true
                      decision:
                        type: string
                        nullable: true
                      archived_at:
                        nullable: true
                    required:
                      - id
                      - topic
                      - decision
                      - archived_at
                  message:
                    type: string
                  operation:
                    type: string
                    enum:
                      - decision.restore
                required:
                  - success
                  - decision
                  - message
                  - operation
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/{id}/history:
    get:
      summary: Get decision history
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      responses:
        "200":
          description: Decision change history
          content:
            application/json:
              schema:
                type: object
                properties:
                  history:
                    type: array
                    items:
                      $ref: "#/components/schemas/DecisionHistoryEntry"
                required:
                  - history
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/{id}/assign:
    post:
      summary: Assign decision
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
      requestBody:
        description: "At least one of user_id or email required; send email: null to unassign"
        content:
          application/json:
            schema:
              type: object
              properties:
                user_id:
                  type: string
                  nullable: true
                  minLength: 1
                email:
                  type: string
                  nullable: true
                  format: email
                send_invite:
                  type: boolean
                  default: false
                stripe_idempotency_key:
                  type: string
                stripeIdempotencyKey:
                  type: string
      responses:
        "200":
          description: Decision assigned
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  decision:
                    type: object
                    properties:
                      id:
                        type: string
                      topic:
                        type: string
                        nullable: true
                      decision:
                        type: string
                        nullable: true
                      confirmation_status:
                        type: string
                        nullable: true
                      assigned_to_user_id:
                        type: string
                        nullable: true
                      assigned_to_email:
                        type: string
                        nullable: true
                    required:
                      - id
                      - topic
                      - decision
                      - confirmation_status
                      - assigned_to_user_id
                      - assigned_to_email
                  message:
                    type: string
                  invite_sent:
                    type: boolean
                required:
                  - success
                  - decision
                  - message
                  - invite_sent
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/{id}/context:
    get:
      summary: Get decision context
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Decision ID (e.g. D-123)
          required: true
          description: Decision ID (e.g. D-123)
          name: id
          in: path
        - schema:
            type: boolean
          required: false
          name: semantic
          in: query
        - schema:
            type: integer
            default: 5
          required: false
          name: semantic_limit
          in: query
      responses:
        "200":
          description: Decision with surrounding context
          content:
            application/json:
              schema:
                type: object
                properties:
                  decision:
                    $ref: "#/components/schemas/Decision"
                  related_decisions:
                    type: array
                    items:
                      $ref: "#/components/schemas/Decision"
                  semantic_matches:
                    type: array
                    items:
                      type: object
                      additionalProperties:
                        nullable: true
                required:
                  - decision
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/propose:
    post:
      summary: Propose a decision from detected text
      tags:
        - Decisions
      security: *a3
      requestBody:
        description: Proposal from detected decision text
        content:
          application/json:
            schema:
              type: object
              properties:
                detected_text:
                  type: string
                rationale:
                  type: string
                source_context:
                  type: string
                confidence:
                  type: number
                category:
                  type: string
                severity:
                  type: string
                confirm:
                  type: boolean
              required:
                - detected_text
      responses:
        "201":
          description: Proposal created
          content:
            application/json:
              schema:
                type: object
                properties:
                  proposal_id:
                    type: string
                  preview:
                    type: object
                    additionalProperties:
                      nullable: true
                  auto_confirmed:
                    type: boolean
                  decision:
                    $ref: "#/components/schemas/Decision"
                  confidence_score:
                    type: number
                  requires_confirmation:
                    type: boolean
                required:
                  - confidence_score
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/session:
    post:
      summary: Session decisions (retired BRI-3128)
      description: Retired in BRI-3128. session_decisions consolidated onto the decisions table. Use POST
        /api/v1/decisions/record with `isolation_key` for scoped writes, POST /api/v1/decisions/propose for AI-detected
        proposals, GET /api/v1/decisions?isolation_key=<key> for scoped reads.
      deprecated: true
      tags:
        - Decisions
      security: *a3
      responses:
        "410":
          description: Endpoint retired
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  migration:
                    type: object
                    properties:
                      ai_proposals:
                        type: string
                      scoped_decisions:
                        type: string
                      list_proposals:
                        type: string
                      list_scoped:
                        type: string
                    required:
                      - ai_proposals
                      - scoped_decisions
                      - list_proposals
                      - list_scoped
                required:
                  - error
                  - migration
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
    get:
      summary: Session decisions (retired BRI-3128)
      description: Retired in BRI-3128. session_decisions consolidated onto the decisions table. Use POST
        /api/v1/decisions/record with `isolation_key` for scoped writes, POST /api/v1/decisions/propose for AI-detected
        proposals, GET /api/v1/decisions?isolation_key=<key> for scoped reads.
      deprecated: true
      tags:
        - Decisions
      security: *a3
      responses:
        "410":
          description: Endpoint retired
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  migration:
                    type: object
                    properties:
                      ai_proposals:
                        type: string
                      scoped_decisions:
                        type: string
                      list_proposals:
                        type: string
                      list_scoped:
                        type: string
                    required:
                      - ai_proposals
                      - scoped_decisions
                      - list_proposals
                      - list_scoped
                required:
                  - error
                  - migration
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
    delete:
      summary: Session decisions (retired BRI-3128)
      description: Retired in BRI-3128. session_decisions consolidated onto the decisions table. Use POST
        /api/v1/decisions/record with `isolation_key` for scoped writes, POST /api/v1/decisions/propose for AI-detected
        proposals, GET /api/v1/decisions?isolation_key=<key> for scoped reads.
      deprecated: true
      tags:
        - Decisions
      security: *a3
      responses:
        "410":
          description: Endpoint retired
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  migration:
                    type: object
                    properties:
                      ai_proposals:
                        type: string
                      scoped_decisions:
                        type: string
                      list_proposals:
                        type: string
                      list_scoped:
                        type: string
                    required:
                      - ai_proposals
                      - scoped_decisions
                      - list_proposals
                      - list_scoped
                required:
                  - error
                  - migration
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
  /api/v1/decisions/pending:
    get:
      summary: List pending decisions
      tags:
        - Decisions
      security: *a3
      responses:
        "200":
          description: Pending decisions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Decision"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/tags:
    get:
      summary: List all decision tags
      tags:
        - Decisions
      security: *a3
      responses:
        "200":
          description: Tags in use with their usage counts, most used first
          content:
            application/json:
              schema:
                type: object
                properties:
                  tags:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                        count:
                          type: integer
                      required:
                        - name
                        - count
                  total:
                    type: integer
                  include_archived:
                    type: boolean
                required:
                  - tags
                  - total
                  - include_archived
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/confirm:
    post:
      summary: Confirm decision
      tags:
        - Decisions
      security: *a3
      requestBody:
        description: Decision ID to confirm
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: string
              required:
                - id
      responses:
        "200":
          description: Confirmation result
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  confirmed:
                    type: number
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/batch-propose:
    post:
      summary: Batch propose decisions
      tags:
        - Decisions
      security: *a3
      requestBody:
        description: Array of proposals
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                properties:
                  detected_text:
                    type: string
                  rationale:
                    type: string
                  source_context:
                    type: string
                  confidence:
                    type: number
                  category:
                    type: string
                  severity:
                    type: string
                required:
                  - detected_text
      responses:
        "200":
          description: Batch proposal results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      additionalProperties:
                        nullable: true
                required:
                  - results
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/approve-suggestions:
    post:
      summary: Approve AI suggestions
      tags:
        - Decisions
      security: *a3
      requestBody:
        description: Suggestion IDs to approve
        content:
          application/json:
            schema:
              type: object
              properties:
                approvedIds:
                  type: array
                  items:
                    type: string
              required:
                - approvedIds
      responses:
        "200":
          description: Suggestions approved
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/reject-suggestions:
    post:
      summary: Reject AI suggestions
      tags:
        - Decisions
      security: *a3
      requestBody:
        description: Suggestions to reject
        content:
          application/json:
            schema:
              type: object
              properties:
                suggestionIds:
                  type: array
                  items:
                    type: string
                reason:
                  type: string
                note:
                  type: string
                similarToId:
                  type: string
              required:
                - suggestionIds
      responses:
        "200":
          description: Suggestions rejected
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/proposals:
    get:
      summary: List proposals
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            enum:
              - pending
              - confirmed
              - rejected
          required: false
          name: status
          in: query
        - schema:
            type: number
            minimum: 0
            maximum: 1
          required: false
          name: min_confidence
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
          required: false
          name: limit
          in: query
      responses:
        "200":
          description: Decision proposals
          content:
            application/json:
              schema:
                type: object
                properties:
                  proposals:
                    type: array
                    items:
                      type: object
                      properties:
                        proposal_id:
                          type: string
                        detected_text:
                          type: string
                          nullable: true
                        proposed_decision:
                          type: string
                        proposed_rationale:
                          type: string
                          nullable: true
                        confidence_score:
                          type: number
                        source_context:
                          type: array
                          nullable: true
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                              source_type:
                                type: string
                              source_url:
                                type: string
                              source_context:
                                type: object
                                additionalProperties:
                                  nullable: true
                              extracted_at:
                                type: string
                                format: date-time
                            additionalProperties:
                              nullable: true
                        suggested_category:
                          type: string
                          nullable: true
                        suggested_severity:
                          type: string
                          nullable: true
                        suggested_tags:
                          type: array
                          items:
                            type: string
                        status:
                          type: string
                          enum:
                            - pending
                            - confirmed
                            - rejected
                        created_at:
                          type: string
                      required:
                        - proposal_id
                        - detected_text
                        - proposed_decision
                        - proposed_rationale
                        - confidence_score
                        - source_context
                        - suggested_category
                        - suggested_severity
                        - suggested_tags
                        - status
                        - created_at
                  count:
                    type: number
                  filters_applied:
                    type: object
                    properties:
                      status:
                        type: string
                      min_confidence:
                        anyOf:
                          - type: number
                          - type: string
                            enum:
                              - none
                      limit:
                        type: number
                    required:
                      - status
                      - min_confidence
                      - limit
                required:
                  - proposals
                  - count
                  - filters_applied
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/proposals/confirm:
    post:
      summary: Confirm a proposal
      tags:
        - Decisions
      security: *a3
      requestBody:
        description: Proposal to confirm with optional edits
        content:
          application/json:
            schema:
              type: object
              properties:
                proposal_id:
                  type: string
                edits:
                  type: object
                  additionalProperties:
                    nullable: true
              required:
                - proposal_id
      responses:
        "200":
          description: Confirmed decision
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Decision"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/decisions/seen:
    post:
      summary: Mark unseen decisions seen
      description: Sets seen_at on the caller's currently-unseen decisions (org-wide by default). Pass isolation_key to scope
        the write to exactly what that view could show, mirroring GET /api/v1/decisions's isolation_key semantics.
      tags:
        - Decisions
      security: *a3
      parameters:
        - schema:
            type: string
            description: Isolation-key scope. Omit for org-wide only, empty string for explicit org-wide-only, string for org-wide +
              matching `isolation_key`.
          required: false
          description: Isolation-key scope. Omit for org-wide only, empty string for explicit org-wide-only, string for org-wide +
            matching `isolation_key`.
          name: isolation_key
          in: query
      responses:
        "200":
          description: Decisions marked seen
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  marked:
                    type: number
                    description: Count of decisions marked seen
                  ids:
                    type: array
                    items:
                      type: string
                    description: IDs of decisions marked seen
                required:
                  - ok
                  - marked
                  - ids
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features:
    get:
      tags:
        - Features
      summary: List features
      security: &a4
        - ApiKeyAuth: []
      responses:
        "200":
          description: Feature list
          content:
            application/json:
              schema:
                type: object
                properties:
                  features:
                    type: array
                    items:
                      $ref: "#/components/schemas/Feature"
                required:
                  - features
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Features
      summary: Create feature
      security: *a4
      requestBody:
        description: Feature to create
        content:
          application/json:
            schema:
              type: object
              properties:
                feature:
                  type: object
                  properties:
                    name:
                      type: string
                      minLength: 1
                    description:
                      type: string
                      nullable: true
                    stage:
                      type: string
                      enum:
                        - planned
                        - beta
                        - ga
                        - sunset
                    confidence:
                      type: number
                      minimum: 0
                      maximum: 1
                    visibility:
                      type: string
                      enum:
                        - public
                        - internal
                        - hidden
                    priority:
                      type: integer
                    relatedWorkItems:
                      type: array
                      items:
                        anyOf:
                          - type: string
                            minLength: 1
                            maxLength: 200
                          - type: object
                            properties:
                              sourceId:
                                type: string
                                minLength: 1
                                maxLength: 200
                              sourceType:
                                type: string
                                minLength: 1
                                maxLength: 50
                            required:
                              - sourceId
                              - sourceType
                      maxItems: 50
                  required:
                    - name
              required:
                - feature
      responses:
        "201":
          description: Feature created
          content:
            application/json:
              schema:
                type: object
                properties:
                  feature:
                    $ref: "#/components/schemas/Feature"
                required:
                  - feature
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Features
      summary: Update feature
      description: Updates a feature identified by featureId in the request body. Legacy endpoint — prefer PATCH
        /api/v1/features/{id}.
      security: *a4
      requestBody:
        description: Feature ID and fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                featureId:
                  type: string
                  format: uuid
                updates:
                  type: object
                  properties:
                    name:
                      type: string
                      minLength: 1
                    description:
                      type: string
                      nullable: true
                    stage:
                      type: string
                      enum:
                        - planned
                        - beta
                        - ga
                        - sunset
                    visibility:
                      type: string
                      enum:
                        - public
                        - internal
                        - hidden
                    priority:
                      type: integer
                    confidence:
                      type: number
                      minimum: 0
                      maximum: 1
                    relatedWorkItems:
                      type: array
                      items:
                        anyOf:
                          - type: string
                            minLength: 1
                            maxLength: 200
                          - type: object
                            properties:
                              sourceId:
                                type: string
                                minLength: 1
                                maxLength: 200
                              sourceType:
                                type: string
                                minLength: 1
                                maxLength: 50
                            required:
                              - sourceId
                              - sourceType
                      maxItems: 50
              required:
                - featureId
      responses:
        "200":
          description: Feature updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  feature:
                    $ref: "#/components/schemas/Feature"
                required:
                  - feature
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Features
      summary: Delete feature
      description: Deletes a feature identified by featureId in the request body. Legacy endpoint — prefer DELETE
        /api/v1/features/{id}.
      security: *a4
      requestBody:
        description: Feature ID to delete
        content:
          application/json:
            schema:
              type: object
              properties:
                featureId:
                  type: string
                  format: uuid
              required:
                - featureId
      responses:
        "200":
          description: Feature deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features/{id}:
    get:
      tags:
        - Features
      summary: Get feature
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      responses:
        "200":
          description: Feature details
          content:
            application/json:
              schema:
                type: object
                properties:
                  feature:
                    $ref: "#/components/schemas/Feature"
                required:
                  - feature
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Features
      summary: Update feature by ID
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                description:
                  type: string
                  nullable: true
                stage:
                  type: string
                  enum:
                    - planned
                    - beta
                    - ga
                    - sunset
                confidence:
                  type: number
                  minimum: 0
                  maximum: 1
                visibility:
                  type: string
                  enum:
                    - public
                    - internal
                    - hidden
                priority:
                  type: integer
                relatedWorkItems:
                  type: array
                  items:
                    anyOf:
                      - type: string
                        minLength: 1
                        maxLength: 200
                      - type: object
                        properties:
                          sourceId:
                            type: string
                            minLength: 1
                            maxLength: 200
                          sourceType:
                            type: string
                            minLength: 1
                            maxLength: 50
                        required:
                          - sourceId
                          - sourceType
                  maxItems: 50
      responses:
        "200":
          description: Feature updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  feature:
                    $ref: "#/components/schemas/Feature"
                required:
                  - feature
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    put:
      tags:
        - Features
      summary: Replace feature
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      requestBody:
        description: Full feature replacement
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                description:
                  type: string
                  nullable: true
                stage:
                  type: string
                  enum:
                    - planned
                    - beta
                    - ga
                    - sunset
                confidence:
                  type: number
                  minimum: 0
                  maximum: 1
                visibility:
                  type: string
                  enum:
                    - public
                    - internal
                    - hidden
                priority:
                  type: integer
                relatedWorkItems:
                  type: array
                  items:
                    anyOf:
                      - type: string
                        minLength: 1
                        maxLength: 200
                      - type: object
                        properties:
                          sourceId:
                            type: string
                            minLength: 1
                            maxLength: 200
                          sourceType:
                            type: string
                            minLength: 1
                            maxLength: 50
                        required:
                          - sourceId
                          - sourceType
                  maxItems: 50
              required:
                - name
      responses:
        "200":
          description: Feature replaced
          content:
            application/json:
              schema:
                type: object
                properties:
                  feature:
                    $ref: "#/components/schemas/Feature"
                required:
                  - feature
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Features
      summary: Delete feature by ID
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      responses:
        "200":
          description: Feature deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features/{id}/personas:
    get:
      tags:
        - Features
      summary: List feature personas
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      responses:
        "200":
          description: Linked personas
          content:
            application/json:
              schema:
                type: object
                properties:
                  personas:
                    type: array
                    items:
                      $ref: "#/components/schemas/FeaturePersona"
                required:
                  - personas
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Features
      summary: Link persona to feature
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      requestBody:
        description: Persona to link
        content:
          application/json:
            schema:
              type: object
              properties:
                personaId:
                  type: string
                  format: uuid
              required:
                - personaId
      responses:
        "201":
          description: Persona linked
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features/{id}/personas/{personaId}:
    delete:
      tags:
        - Features
      summary: Unlink persona from feature
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: Persona ID
          required: true
          description: Persona ID
          name: personaId
          in: path
      responses:
        "200":
          description: Persona unlinked
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features/approve:
    post:
      tags:
        - Features
      summary: Approve suggested features
      security: *a4
      requestBody:
        description: Feature IDs to approve
        content:
          application/json:
            schema:
              type: object
              properties:
                featureIds:
                  type: array
                  items:
                    type: string
                    format: uuid
              required:
                - featureIds
      responses:
        "200":
          description: Approved count
          content:
            application/json:
              schema:
                type: object
                properties:
                  approved:
                    type: number
                required:
                  - approved
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features/suggestions:
    get:
      tags:
        - Features
      summary: List AI feature suggestions
      security: *a4
      responses:
        "200":
          description: Feature suggestions
          content:
            application/json:
              schema:
                type: object
                properties:
                  suggestions:
                    type: array
                    items:
                      $ref: "#/components/schemas/PendingFeatureSuggestion"
                required:
                  - suggestions
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features/suggestions/reject:
    post:
      tags:
        - Features
      summary: Reject feature suggestions
      security: *a4
      requestBody:
        description: Feature IDs to reject
        content:
          application/json:
            schema:
              type: object
              properties:
                featureIds:
                  type: array
                  items:
                    type: string
                    format: uuid
              required:
                - featureIds
      responses:
        "200":
          description: Rejected count
          content:
            application/json:
              schema:
                type: object
                properties:
                  rejected:
                    type: number
                required:
                  - rejected
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features/{id}/lifecycle-events:
    get:
      tags:
        - Features
      summary: List feature lifecycle events
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      responses:
        "200":
          description: Feature lifecycle history
          content:
            application/json:
              schema:
                type: object
                properties:
                  lifecycle_events:
                    type: array
                    items:
                      $ref: "#/components/schemas/FeatureLifecycleEvent"
                required:
                  - lifecycle_events
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Features
      summary: Record feature lifecycle event
      security: *a4
      parameters:
        - schema:
            type: string
            format: uuid
            description: Feature ID
          required: true
          description: Feature ID
          name: id
          in: path
      requestBody:
        description: Evidence-backed lifecycle event
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateFeatureLifecycleEvent"
      responses:
        "201":
          description: Feature lifecycle event created
          content:
            application/json:
              schema:
                type: object
                properties:
                  lifecycle_event:
                    $ref: "#/components/schemas/FeatureLifecycleEvent"
                required:
                  - lifecycle_event
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/user-intelligence/personas:
    get:
      tags:
        - Personas
      summary: List personas
      security: &a5
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            nullable: true
            enum:
              - high
              - medium
              - low
              - null
          required: false
          name: priority
          in: query
        - schema:
            type: string
            nullable: true
          required: false
          name: sources
          in: query
      responses:
        "200":
          description: Persona list
          content:
            application/json:
              schema:
                type: object
                properties:
                  personas:
                    type: array
                    items:
                      $ref: "#/components/schemas/Persona"
                  total:
                    type: number
                required:
                  - personas
                  - total
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Personas
      summary: Create persona
      security: *a5
      requestBody:
        description: Persona to create
        content:
          application/json:
            schema:
              type: object
              properties:
                persona:
                  type: object
                  properties:
                    segment_name:
                      type: string
                      minLength: 1
                    description:
                      type: string
                      nullable: true
                    priority:
                      type: string
                      enum:
                        - high
                        - medium
                        - low
                    needs:
                      type: array
                      items:
                        type: string
                    pain_points:
                      type: array
                      items:
                        type: string
                    quotes:
                      type: array
                      items:
                        type: object
                        properties:
                          text:
                            type: string
                          date:
                            type: string
                          call_id:
                            type: string
                        required:
                          - text
                          - date
                  required:
                    - segment_name
              required:
                - persona
      responses:
        "200":
          description: Persona created
          content:
            application/json:
              schema:
                type: object
                properties:
                  persona:
                    $ref: "#/components/schemas/Persona"
                required:
                  - persona
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Personas
      summary: Update persona
      security: *a5
      requestBody:
        description: Persona ID and fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                personaId:
                  type: string
                  format: uuid
                updates:
                  type: object
                  properties:
                    segment_name:
                      type: string
                      minLength: 1
                    description:
                      type: string
                      nullable: true
                    priority:
                      type: string
                      enum:
                        - high
                        - medium
                        - low
                    needs:
                      type: array
                      items:
                        type: string
                    pain_points:
                      type: array
                      items:
                        type: string
                    quotes:
                      type: array
                      items:
                        type: object
                        properties:
                          text:
                            type: string
                          date:
                            type: string
                          call_id:
                            type: string
                        required:
                          - text
                          - date
              required:
                - personaId
                - updates
      responses:
        "200":
          description: Persona updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  persona:
                    $ref: "#/components/schemas/Persona"
                required:
                  - persona
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Personas
      summary: Delete persona
      security: *a5
      parameters:
        - schema:
            type: string
            format: uuid
            description: Persona ID to delete
          required: true
          description: Persona ID to delete
          name: personaId
          in: query
      responses:
        "200":
          description: Persona deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/user-intelligence/personas/approve:
    post:
      tags:
        - Personas
      summary: Approve suggested personas
      security: *a5
      responses:
        "200":
          description: Approved count
          content:
            application/json:
              schema:
                type: object
                properties:
                  approved:
                    type: number
                required:
                  - approved
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/user-intelligence/personas/pending:
    get:
      tags:
        - Personas
      summary: List pending personas
      security: *a5
      responses:
        "200":
          description: Pending personas
          content:
            application/json:
              schema:
                type: object
                properties:
                  personas:
                    type: array
                    items:
                      $ref: "#/components/schemas/Persona"
                required:
                  - personas
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/user-intelligence/personas/reject:
    post:
      tags:
        - Personas
      summary: Reject suggested personas
      security: *a5
      responses:
        "200":
          description: Rejected count
          content:
            application/json:
              schema:
                type: object
                properties:
                  rejected:
                    type: number
                required:
                  - rejected
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/conversations:
    get:
      tags:
        - Conversations
      summary: List conversations
      security: &a6
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: integer
            maximum: 100
            default: 20
          required: false
          name: limit
          in: query
        - schema:
            type: integer
          required: false
          name: offset
          in: query
        - schema:
            type: string
          required: false
          name: cursor
          in: query
        - schema:
            type: string
            enum:
              - human
              - agent
          required: false
          name: source
          in: query
      responses:
        "200":
          description: Paginated conversation list
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversations:
                    type: array
                    items:
                      allOf:
                        - $ref: "#/components/schemas/Conversation"
                        - type: object
                          properties:
                            preview:
                              type: string
                              nullable: true
                          required:
                            - preview
                  has_more:
                    type: boolean
                  next_cursor:
                    type: string
                    nullable: true
                required:
                  - conversations
                  - has_more
                  - next_cursor
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Conversations
      summary: Create conversation
      security: *a6
      requestBody:
        description: Conversation to create
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  minLength: 1
                  maxLength: 200
                context_folder_id:
                  type: string
                  format: uuid
                context_document_ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  maxItems: 50
                model:
                  type: string
                metadata:
                  type: object
                  additionalProperties:
                    nullable: true
                  default: {}
      responses:
        "201":
          description: Created conversation
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversation:
                    $ref: "#/components/schemas/Conversation"
                required:
                  - conversation
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/conversations/{id}:
    get:
      tags:
        - Conversations
      summary: Get conversation with messages
      security: *a6
      parameters:
        - schema:
            type: string
            description: Conversation ID
          required: true
          description: Conversation ID
          name: id
          in: path
      responses:
        "200":
          description: Conversation with messages
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversation:
                    allOf:
                      - $ref: "#/components/schemas/Conversation"
                      - type: object
                        properties:
                          context_entity_refs:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: string
                                entityType:
                                  type: string
                                title:
                                  type: string
                              required:
                                - id
                                - entityType
                                - title
                          messages:
                            type: array
                            items:
                              $ref: "#/components/schemas/Message"
                          user_feedback:
                            type: object
                            additionalProperties:
                              type: boolean
                        required:
                          - context_entity_refs
                          - messages
                          - user_feedback
                required:
                  - conversation
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Conversations
      summary: Update conversation
      security: *a6
      parameters:
        - schema:
            type: string
            description: Conversation ID
          required: true
          description: Conversation ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  minLength: 1
                  maxLength: 200
                context_folder_id:
                  type: string
                  format: uuid
                context_document_ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  maxItems: 50
                model:
                  type: string
                metadata:
                  type: object
                  additionalProperties:
                    nullable: true
                starred:
                  type: boolean
      responses:
        "200":
          description: Updated conversation
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversation:
                    $ref: "#/components/schemas/Conversation"
                required:
                  - conversation
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Conversations
      summary: Delete conversation
      security: *a6
      parameters:
        - schema:
            type: string
            description: Conversation ID
          required: true
          description: Conversation ID
          name: id
          in: path
      responses:
        "204":
          description: No content
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/conversations/{id}/context-status:
    get:
      tags:
        - Conversations
      summary: Get context status
      security: *a6
      parameters:
        - schema:
            type: string
            description: Conversation ID
          required: true
          description: Conversation ID
          name: id
          in: path
      responses:
        "200":
          description: Context status
          content:
            application/json:
              schema:
                type: object
                properties:
                  total_tokens:
                    type: number
                  raw_total_tokens:
                    type: number
                  unsummarized_turn_count:
                    type: number
                  assembled_message_count:
                    type: number
                  summary:
                    type: string
                    nullable: true
                  model_context_window:
                    type: number
                  compaction_in_progress:
                    type: boolean
                  needs_compaction:
                    type: boolean
                  recently_compacted:
                    type: boolean
                required:
                  - total_tokens
                  - raw_total_tokens
                  - unsummarized_turn_count
                  - assembled_message_count
                  - summary
                  - model_context_window
                  - compaction_in_progress
                  - needs_compaction
                  - recently_compacted
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/conversations/{id}/restore:
    post:
      tags:
        - Conversations
      summary: Restore a deleted conversation
      description: Undoes a delete. Answers 404 when the conversation is not deleted.
      security: *a6
      parameters:
        - schema:
            type: string
            description: Conversation ID
          required: true
          description: Conversation ID
          name: id
          in: path
      responses:
        "200":
          description: Restored conversation
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversation:
                    $ref: "#/components/schemas/Conversation"
                required:
                  - conversation
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/conversations/{id}/live:
    get:
      tags:
        - Conversations
      summary: Poll a conversation for changes
      description: Returns the current conversation with its messages and a `revision`. Pass the last `revision` back; the
        route answers 204 while nothing has changed.
      security: *a6
      parameters:
        - schema:
            type: string
            description: Conversation ID
          required: true
          description: Conversation ID
          name: id
          in: path
        - schema:
            type: string
          required: false
          name: revision
          in: query
      responses:
        "200":
          description: Conversation and its revision
          content:
            application/json:
              schema:
                type: object
                properties:
                  revision:
                    type: string
                  conversation:
                    allOf:
                      - $ref: "#/components/schemas/Conversation"
                      - type: object
                        properties:
                          messages:
                            type: array
                            items:
                              anyOf:
                                - $ref: "#/components/schemas/Message"
                                - $ref: "#/components/schemas/LiveReplayMessage"
                        required:
                          - messages
                required:
                  - revision
                  - conversation
        "204":
          description: Nothing changed since `revision`
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/conversations/{id}/stream:
    get:
      tags:
        - Conversations
      summary: Resume or observe the active turn of a conversation
      description: Server-sent events replay of the turn. Answers 204 when no turn is active; the `X-Chat-Turn-Completed`
        header then names the last completed turn.
      security: *a6
      parameters:
        - schema:
            type: string
            description: Conversation ID
          required: true
          description: Conversation ID
          name: id
          in: path
        - schema:
            type: string
          required: false
          name: chatTurnId
          in: query
      responses:
        "200":
          description: Event stream of the turn
          content:
            text/event-stream:
              schema:
                type: string
        "204":
          description: No active turn
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/chat/feedback:
    post:
      tags:
        - Chat
      summary: Submit chat feedback
      security: *a6
      requestBody:
        description: Feedback payload
        content:
          application/json:
            schema:
              type: object
              properties:
                messageId:
                  type: string
                  format: uuid
                conversationId:
                  type: string
                  format: uuid
                rating:
                  type: boolean
                  nullable: true
                feedbackReason:
                  type: string
                  maxLength: 500
              required:
                - messageId
                - conversationId
                - rating
      responses:
        "200":
          description: Feedback submitted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  dbSuccess:
                    type: boolean
                required:
                  - success
                  - dbSuccess
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agents/{name}/custom-mcp-consents:
    get:
      tags:
        - Agents
      summary: List custom MCP tool permissions for an agent
      security:
        - ApiKeyAuth: []
        - ClerkSession: []
      parameters:
        - schema:
            type: string
            description: Agent slug
          required: true
          description: Agent slug
          name: name
          in: path
      responses:
        "200":
          description: Organization-scoped tool permissions
          content:
            application/json:
              schema:
                type: object
                properties:
                  consents:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        serverId:
                          type: string
                          format: uuid
                        serverName:
                          type: string
                        toolName:
                          type: string
                        definitionHash:
                          type: string
                          minLength: 64
                          maxLength: 64
                        status:
                          type: string
                          enum:
                            - pending
                            - allowed
                            - denied
                      required:
                        - id
                        - serverId
                        - serverName
                        - toolName
                        - definitionHash
                        - status
                required:
                  - consents
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Agents
      summary: Allow or deny a background custom MCP write
      description: Requires a human administrator session. Machine credentials cannot grant consent. Approval permits future
        calls and does not replay a held call.
      security:
        - ClerkSession: []
      parameters:
        - schema:
            type: string
            description: Agent slug
          required: true
          description: Agent slug
          name: name
          in: path
      requestBody:
        description: Consent decision for the reviewed tool definition
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: string
                  format: uuid
                definitionHash:
                  type: string
                  minLength: 64
                  maxLength: 64
                status:
                  type: string
                  enum:
                    - allowed
                    - denied
                expectedStatus:
                  type: string
                  enum:
                    - pending
                    - allowed
                    - denied
                  description: Status displayed when the administrator reviewed the request
              required:
                - id
                - definitionHash
                - status
                - expectedStatus
      responses:
        "200":
          description: Permission saved
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                required:
                  - ok
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: The tool or consent changed; refresh and review its current request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agents/trigger:
    post:
      tags:
        - Agents
      summary: Trigger agent run
      security: &a7
        - ApiKeyAuth: []
      requestBody:
        description: Agent trigger payload
        content:
          application/json:
            schema:
              type: object
              properties:
                agentName:
                  type: string
              required:
                - agentName
      responses:
        "200":
          description: Agent run started
          content:
            application/json:
              schema:
                type: object
                properties:
                  runId:
                    type: string
                  status:
                    type: string
                required:
                  - runId
                  - status
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agents/trigger-and-wait:
    post:
      tags:
        - Agents
      summary: Trigger agent and wait for result
      security: *a7
      requestBody:
        description: Agent trigger payload
        content:
          application/json:
            schema:
              type: object
              properties:
                agentName:
                  type: string
              required:
                - agentName
      responses:
        "200":
          description: Agent run result
          content:
            application/json:
              schema:
                type: object
                properties:
                  runId:
                    type: string
                  status:
                    type: string
                  result:
                    nullable: true
                required:
                  - runId
                  - status
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agents/list:
    get:
      tags:
        - Agents
      summary: List available agents
      security: *a7
      responses:
        "200":
          description: Available agents
          content:
            application/json:
              schema:
                type: object
                properties:
                  agents:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                        description:
                          type: string
                        status:
                          type: string
                      required:
                        - name
                        - description
                        - status
                required:
                  - agents
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agents/status:
    get:
      tags:
        - Agents
      summary: Get all agent statuses
      security: *a7
      responses:
        "200":
          description: All agent run statuses, bucketed by the latest run in the last 24 hours
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  running:
                    type: array
                    items:
                      type: string
                    description: Agent names whose latest 24h run is queued or running
                  completed:
                    type: array
                    items:
                      type: string
                  failed:
                    type: array
                    items:
                      type: string
                  cancelled:
                    type: array
                    items:
                      type: string
                    description: Agent names whose latest 24h run was cancelled by a user
                  total:
                    type: number
                    description: Agents with a run in the window; the four arrays partition this
                required:
                  - success
                  - running
                  - completed
                  - failed
                  - cancelled
                  - total
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agents/status/{runId}:
    get:
      tags:
        - Agents
      summary: Get specific run status
      security: *a7
      parameters:
        - schema:
            type: string
            description: Agent run ID
          required: true
          description: Agent run ID
          name: runId
          in: path
      responses:
        "200":
          description: Agent run status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentRunStatus"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agents/{name}/runs/{runId}/cancel:
    post:
      tags:
        - Agents
      summary: Cancel a running agent run
      description: Admin-only. Works for any agent run this API can look up — a created agent or a built-in/cutover agent
        (BRI-6391). Returns one structured result; success is never inferred from the request having been sent.
        `already_terminal` with `delivery_in_flight` means the run had already claimed delivery and could not be
        stopped.
      security: *a7
      parameters:
        - schema:
            type: string
            description: Agent slug
          required: true
          description: Agent slug
          name: name
          in: path
        - schema:
            type: string
            description: Agent run ID
          required: true
          description: Agent run ID
          name: runId
          in: path
      requestBody:
        description: Cancellation request
        content:
          application/json:
            schema:
              type: object
              properties:
                request_id:
                  type: string
                  minLength: 1
                  maxLength: 200
                  description: Client-generated id held for one confirmation and reused on retry; this is what makes a repeat idempotent.
              required:
                - request_id
      responses:
        "200":
          description: Cancellation outcome
          content:
            application/json:
              schema:
                type: object
                properties:
                  result:
                    type: string
                    enum:
                      - cancelled
                      - already_cancelled
                      - already_terminal
                  run:
                    type: object
                    properties:
                      id:
                        type: string
                      agentName:
                        type: string
                      status:
                        type: string
                    required:
                      - id
                      - agentName
                      - status
                  delivery_in_flight:
                    type: boolean
                required:
                  - result
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/skills:
    get:
      tags:
        - Skills
      summary: List skills
      security: &a8
        - ApiKeyAuth: []
        - ClerkSession: []
      responses:
        "200":
          description: Skills list
          content:
            application/json:
              schema:
                type: object
                properties:
                  skills:
                    type: array
                    items:
                      $ref: "#/components/schemas/SkillSummary"
                  total:
                    type: number
                required:
                  - skills
                  - total
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Skills
      summary: Create skill from markdown content
      security: *a8
      requestBody:
        description: Skill markdown + optional subfolder
        content:
          application/json:
            schema:
              type: object
              properties:
                markdown:
                  type: string
                  minLength: 1
                subfolder:
                  type: string
                  enum:
                    - Built-in
                    - Integrations
                    - Team
                    - Settings
              required:
                - markdown
      responses:
        "201":
          description: Skill created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SkillWriteResult"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Conflict (duplicate skill name)
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - error
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/skills/{name}:
    get:
      tags:
        - Skills
      summary: Get skill by name
      security: *a8
      parameters:
        - schema:
            type: string
            minLength: 1
          required: true
          name: name
          in: path
      responses:
        "200":
          description: Skill details
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                  title:
                    type: string
                  description:
                    type: string
                  content:
                    type: string
                  resolvedVersion:
                    type: string
                    nullable: true
                required:
                  - name
                  - title
                  - description
                  - content
                  - resolvedVersion
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Skills
      summary: Update skill content
      security: *a8
      parameters:
        - schema:
            type: string
            minLength: 1
          required: true
          name: name
          in: path
      requestBody:
        description: Replacement markdown. Teachable-skill overlays may change the body, description, triggers, and model; other
          frontmatter changes are rejected.
        content:
          application/json:
            schema:
              type: object
              properties:
                markdown:
                  type: string
                  minLength: 1
                expectedResolvedVersion:
                  type: string
                  minLength: 1
              required:
                - markdown
      responses:
        "200":
          description: Skill updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SkillWriteResult"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Conflict (stale resolved version or blocked rename)
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - error
        "413":
          description: Skill content is too large
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - error
        "422":
          description: Skill edit rejected by the coherence gate
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        enum:
                          - GATE_REJECTED
                      message:
                        type: string
                      blockedReasons:
                        type: array
                        items:
                          type: string
                    required:
                      - code
                      - message
                required:
                  - error
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Skills
      summary: Archive skill (soft delete)
      security: *a8
      parameters:
        - schema:
            type: string
            minLength: 1
          required: true
          name: name
          in: path
      responses:
        "200":
          description: Skill archived
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SkillArchiveResult"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Conflict (integration skill cannot be archived while integration is connected — BRI-1451)
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - error
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/skills/{name}/export:
    get:
      tags:
        - Skills
      summary: Export skill
      security: *a8
      parameters:
        - schema:
            type: string
            minLength: 1
          required: true
          name: name
          in: path
        - schema:
            type: string
            enum:
              - "true"
              - "false"
          required: false
          name: download
          in: query
      responses:
        "200":
          description: Skill markdown content
          content:
            text/markdown:
              schema:
                type: string
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/skills/import:
    post:
      tags:
        - Skills
      summary: Import skill from URL
      security: *a8
      requestBody:
        description: Skill import data
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required:
                - url
      responses:
        "200":
          description: Skill imported
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SkillImportResult"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/context/search:
    get:
      tags:
        - Context
      summary: Search context
      security: &a9
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
          required: true
          name: query
          in: query
        - schema:
            type: number
            nullable: true
          required: false
          name: limit
          in: query
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      properties: {}
                      additionalProperties:
                        nullable: true
                required:
                  - results
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/context/browse:
    get:
      tags:
        - Context
      summary: Browse context
      security: *a9
      parameters:
        - schema:
            type: string
          required: false
          name: path
          in: query
        - schema:
            type: number
            nullable: true
          required: false
          name: depth
          in: query
      responses:
        "200":
          description: Browse results
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties: {}
                      additionalProperties:
                        nullable: true
                required:
                  - items
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/context/find-related:
    post:
      tags:
        - Context
      summary: Find related context
      security: *a9
      requestBody:
        description: Related context query
        content:
          application/json:
            schema:
              type: object
              properties:
                document_id:
                  type: string
                query:
                  type: string
                limit:
                  type: number
                  nullable: true
      responses:
        "200":
          description: Related context items
          content:
            application/json:
              schema:
                type: object
                properties:
                  related:
                    type: array
                    items:
                      type: object
                      properties: {}
                      additionalProperties:
                        nullable: true
                required:
                  - related
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/context/recent:
    get:
      tags:
        - Context
      summary: Get recent context
      security: *a9
      parameters:
        - schema:
            type: number
            nullable: true
          required: false
          name: limit
          in: query
      responses:
        "200":
          description: Recent context items
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties: {}
                      additionalProperties:
                        nullable: true
                required:
                  - items
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/bulk/move:
    post:
      tags:
        - Bulk Operations
      summary: Bulk move items
      security: &a10
        - ApiKeyAuth: []
      requestBody:
        description: Items to move and target folder
        content:
          application/json:
            schema:
              type: object
              properties:
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      type:
                        type: string
                        enum:
                          - document
                          - folder
                    required:
                      - id
                      - type
                  minItems: 1
                  maxItems: 100
                  description: Items to move (max 100)
                folder_id:
                  type: string
                  format: uuid
                  description: Destination folder ID (required - nothing lives at root)
              required:
                - items
                - folder_id
      responses:
        "200":
          description: Bulk move result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BulkMoveResult"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/bulk/delete:
    post:
      tags:
        - Bulk Operations
      summary: Bulk delete items
      security: *a10
      requestBody:
        description: Items to delete
        content:
          application/json:
            schema:
              type: object
              properties:
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      type:
                        type: string
                        enum:
                          - document
                          - folder
                    required:
                      - id
                      - type
                  minItems: 1
                  maxItems: 100
                  description: Items to delete (max 100)
              required:
                - items
      responses:
        "200":
          description: Bulk delete result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BulkDeleteResult"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/api-keys:
    get:
      tags:
        - API Keys
      summary: List organization API keys
      security: &a11
        - ApiKeyAuth: []
      responses:
        "200":
          description: Organization API keys
          content:
            application/json:
              schema:
                type: object
                properties:
                  keys:
                    type: array
                    items:
                      $ref: "#/components/schemas/ApiKey"
                required:
                  - keys
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - API Keys
      summary: Create organization API key
      security: *a11
      requestBody:
        description: API key to create
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
      responses:
        "200":
          description: Created API key (secret shown only once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  key:
                    $ref: "#/components/schemas/ApiKeyCreated"
                required:
                  - key
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/api-keys/{id}:
    patch:
      tags:
        - API Keys
      summary: Update API key (rename or rotate)
      security: *a11
      parameters:
        - schema:
            type: string
            description: API key ID
          required: true
          description: API key ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                rotate:
                  type: boolean
      responses:
        "200":
          description: OK, or new secret if rotated
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    properties:
                      ok:
                        type: boolean
                        enum:
                          - true
                    required:
                      - ok
                  - type: object
                    properties:
                      secret:
                        type: string
                    required:
                      - secret
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - API Keys
      summary: Revoke API key
      security: *a11
      parameters:
        - schema:
            type: string
            description: API key ID
          required: true
          description: API key ID
          name: id
          in: path
      responses:
        "200":
          description: Key revoked
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                required:
                  - ok
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/api-keys/personal:
    get:
      tags:
        - API Keys
      summary: List personal API keys
      security: *a11
      responses:
        "200":
          description: Personal API keys
          content:
            application/json:
              schema:
                type: object
                properties:
                  keys:
                    type: array
                    items:
                      $ref: "#/components/schemas/ApiKey"
                required:
                  - keys
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - API Keys
      summary: Create personal API key
      security: *a11
      requestBody:
        description: Personal API key to create
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 100
                scopes:
                  type: array
                  items:
                    type: string
                    enum:
                      - read
                      - write
                  minItems: 1
                  default:
                    - read
                    - write
              required:
                - name
      responses:
        "200":
          description: Created personal API key (secret shown only once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  key:
                    $ref: "#/components/schemas/ApiKeyCreated"
                required:
                  - key
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/api-keys/personal/{id}:
    get:
      tags:
        - API Keys
      summary: Get personal API key
      security: *a11
      parameters:
        - schema:
            type: string
            description: API key ID
          required: true
          description: API key ID
          name: id
          in: path
      responses:
        "200":
          description: Personal API key details
          content:
            application/json:
              schema:
                type: object
                properties:
                  key:
                    $ref: "#/components/schemas/ApiKey"
                required:
                  - key
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - API Keys
      summary: Update personal API key
      security: *a11
      parameters:
        - schema:
            type: string
            description: API key ID
          required: true
          description: API key ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                rotate:
                  type: boolean
      responses:
        "200":
          description: OK, or new secret if rotated
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    properties:
                      ok:
                        type: boolean
                        enum:
                          - true
                    required:
                      - ok
                  - type: object
                    properties:
                      secret:
                        type: string
                    required:
                      - secret
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - API Keys
      summary: Revoke personal API key
      security: *a11
      parameters:
        - schema:
            type: string
            description: API key ID
          required: true
          description: API key ID
          name: id
          in: path
      responses:
        "200":
          description: Key revoked
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                required:
                  - ok
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/research-signals:
    get:
      tags:
        - Research Signals
      summary: List research signals
      security: &a12
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            description: Comma-separated source filter
          required: false
          description: Comma-separated source filter
          name: source
          in: query
        - schema:
            type: string
            description: Comma-separated signal type filter
          required: false
          description: Comma-separated signal type filter
          name: signal_type
          in: query
        - schema:
            type: string
          required: false
          name: theme
          in: query
        - schema:
            type: number
            minimum: 1
            maximum: 100
            description: Page size (1-100). Omit to return the full canonical set in one response.
          required: false
          description: Page size (1-100). Omit to return the full canonical set in one response.
          name: limit
          in: query
        - schema:
            type: number
            nullable: true
            default: 0
          required: false
          name: offset
          in: query
        - schema:
            type: string
            enum:
              - frequency
              - last_detected
          required: false
          name: order_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
          required: false
          name: order
          in: query
      responses:
        "200":
          description: Paginated signal list
          content:
            application/json:
              schema:
                type: object
                properties:
                  signals:
                    type: array
                    items:
                      $ref: "#/components/schemas/ResearchSignalListItem"
                  total:
                    type: number
                  limit:
                    type: number
                  offset:
                    type: number
                  has_more:
                    type: boolean
                required:
                  - signals
                  - total
                  - limit
                  - offset
                  - has_more
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Research Signals
      summary: Create or update research signal
      description: New themes require a captured quote from a signal in the same organization. Supply metadata.quotes with
        quote_sources (text, source, external_id), or quotes_with_anchor pointing to the captured native source. Native
        call quotes remain eligible without an attributed customer. The server copies verified attribution, anchors and
        source dates, drops unsupported excerpts individually, and returns 400 if none remain. A context-only update to
        an existing theme does not need to resubmit evidence.
      security: *a12
      requestBody:
        description: Signal to create
        content:
          application/json:
            schema:
              type: object
              properties:
                theme:
                  type: string
                  minLength: 1
                source:
                  type: string
                  enum:
                    - fireflies
                    - fathom
                    - granola
                    - gong
                    - zoom
                    - notion
                    - confluence
                    - google_docs
                    - brief
                    - manual
                    - slack
                    - slack_research
                    - langfuse
                    - posthog_llm
                    - hubspot
                    - lightfield
                    - attio
                    - clarify
                    - deal
                signal_type:
                  type: string
                  enum:
                    - request
                    - pain_point
                    - validation
                    - churn_risk
                confidence:
                  type: number
                  minimum: 0
                  maximum: 1
                metadata:
                  type: object
                  nullable: true
                  properties:
                    quotes:
                      type: array
                      items:
                        type: string
                    quote_sources:
                      type: array
                      items:
                        type: object
                        properties:
                          text:
                            type: string
                          source:
                            type: string
                          external_id:
                            type: string
                          source_url:
                            type: string
                        required:
                          - text
                          - source
                          - external_id
                    quotes_with_anchor:
                      type: array
                      items:
                        type: object
                        properties:
                          text:
                            type: string
                          anchor:
                            type: object
                            nullable: true
                            properties:
                              entity_object_id:
                                type: string
                                format: uuid
                            required:
                              - entity_object_id
                            description: Copy the native source anchor from a captured quote. A null or missing anchor requires a verifiable
                              quote_sources reference; otherwise the quote is dropped.
                            example: null
                        required:
                          - text
                  additionalProperties:
                    nullable: true
                  description: New themes require at least one verifiable captured quote with quote_sources or quotes_with_anchor; missing
                    or empty evidence returns 400. Existing themes accept context-only metadata updates, so evidence
                    fields are optional in this shared create/update schema. Source content hashes and supersession
                    markers are server-managed.
                related_decisions:
                  type: array
                  items:
                    type: string
              required:
                - theme
                - source
                - confidence
              additionalProperties: false
      responses:
        "200":
          description: Signal created or updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  signal_id:
                    type: string
                required:
                  - success
                  - signal_id
        "400":
          description: Invalid input, or no verifiable captured customer quote remains.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/research-signals/{id}:
    get:
      tags:
        - Research Signals
      summary: Get research signal
      security: *a12
      parameters:
        - schema:
            type: string
            description: Research signal ID
          required: true
          description: Research signal ID
          name: id
          in: path
      responses:
        "200":
          description: Research signal
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResearchSignal"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Research Signals
      summary: Update research signal
      security: *a12
      parameters:
        - schema:
            type: string
            description: Research signal ID
          required: true
          description: Research signal ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                urgency:
                  type: string
                  enum:
                    - low
                    - medium
                    - high
                status:
                  type: string
                  enum:
                    - new
                    - reviewed
                    - planned
                    - shipped
                    - dismissed
                  description: Signal lifecycle status.
      responses:
        "200":
          description: Signal updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Research Signals
      summary: Delete research signal
      security: *a12
      parameters:
        - schema:
            type: string
            description: Research signal ID
          required: true
          description: Research signal ID
          name: id
          in: path
      responses:
        "200":
          description: Signal deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/user-intelligence/behavior-analytics:
    get:
      tags:
        - User Intelligence
      summary: Get behavior analytics
      security: *a12
      responses:
        "200":
          description: Analytics data
          content:
            application/json:
              schema:
                nullable: true
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/user-intelligence/stats:
    get:
      tags:
        - User Intelligence
      summary: Get user intelligence stats
      security: *a12
      responses:
        "200":
          description: Stats data
          content:
            application/json:
              schema:
                nullable: true
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/work-pipeline:
    get:
      tags:
        - Work Pipeline
      summary: Get work pipeline
      security:
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            enum:
              - full
              - dashboard
              - detail
            default: full
          required: false
          name: view
          in: query
        - schema:
            type: string
            maxLength: 1024
            description: Required for detail view
          required: false
          description: Required for detail view
          name: id
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
          required: false
          name: limit
          in: query
        - schema:
            type: integer
            nullable: true
            minimum: 0
            maximum: 1000000
            default: 0
          required: false
          name: offset
          in: query
      responses:
        "200":
          description: Bounded work pipeline response
          content:
            application/json:
              schema:
                type: object
                properties:
                  work:
                    type: object
                    properties:
                      research:
                        type: array
                        items:
                          $ref: "#/components/schemas/WorkItem"
                      ideas:
                        type: array
                        items:
                          $ref: "#/components/schemas/WorkItem"
                      considering:
                        type: array
                        items:
                          $ref: "#/components/schemas/WorkItem"
                      committed:
                        type: array
                        items:
                          $ref: "#/components/schemas/WorkItem"
                      building:
                        type: array
                        items:
                          $ref: "#/components/schemas/WorkItem"
                      shipped:
                        type: array
                        items:
                          $ref: "#/components/schemas/WorkItem"
                      deprecated:
                        type: array
                        items:
                          $ref: "#/components/schemas/WorkItem"
                      sources:
                        type: array
                        items:
                          type: string
                      last_updated:
                        type: string
                        nullable: true
                    required:
                      - research
                      - ideas
                      - considering
                      - committed
                      - building
                      - shipped
                      - deprecated
                      - sources
                      - last_updated
                  updated_at:
                    type: string
                    nullable: true
                  pagination:
                    type: object
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                      next_offset:
                        type: integer
                        nullable: true
                      has_more:
                        type: boolean
                    required:
                      - limit
                      - offset
                      - next_offset
                      - has_more
                  has_unhealthy_sources:
                    type: boolean
                    description: Current enabled work-source health, checked only for an empty first page.
                  unavailable_sources:
                    type: array
                    items:
                      type: string
                  availability_status:
                    type: string
                    enum:
                      - unknown
                  source_outcomes:
                    type: array
                    items:
                      type: object
                      properties:
                        source:
                          type: string
                        source_binding_id:
                          type: string
                          nullable: true
                          format: uuid
                        availability:
                          type: string
                          enum:
                            - available
                            - unavailable
                            - unknown
                        completeness:
                          type: string
                          enum:
                            - complete
                            - partial
                            - unknown
                        row_count:
                          type: integer
                          nullable: true
                          minimum: 0
                        provenance:
                          type: object
                          nullable: true
                          additionalProperties:
                            nullable: true
                      required:
                        - source
                        - source_binding_id
                        - availability
                        - completeness
                        - row_count
                        - provenance
                required:
                  - work
                  - updated_at
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/entity-links:
    get:
      tags:
        - Entity Links
      summary: List entity links
      security: &a13
        - ApiKeyAuth: []
      responses:
        "200":
          description: Entity link list
          content:
            application/json:
              schema:
                type: object
                properties:
                  links:
                    type: array
                    items:
                      $ref: "#/components/schemas/EntityLink"
                required:
                  - links
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Entity Links
      summary: Create a manual entity link
      description: "Manually links two entities. `source_type` and `target_type` must both be one of the six manual-create
        types recorded by D-568 (BRI-7075/BRI-7197): research_signal, feature, work_item, persona, decision, document.
        Both entities must belong to the caller's organization. If an inactive (rejected) link already exists between
        the same pair, it is reactivated (200, `reactivated: true`) instead of creating a duplicate."
      security: *a13
      requestBody:
        description: Manual entity link to create
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManualEntityLinkCreateRequest"
      responses:
        "200":
          description: Entity link created, or an existing rejected link reactivated
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ManualEntityLinkCreated"
                  - $ref: "#/components/schemas/ManualEntityLinkReactivated"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Source or target entity not found, or does not belong to the caller's organization
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
        "409":
          description: An active (non-rejected) link already exists between this pair
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityLinkConflict"
        "429":
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/EntityLinkRateLimited"
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Entity Links
      summary: Update entity links (bulk)
      security: *a13
      requestBody:
        description: Links to update
        content:
          application/json:
            schema:
              type: object
              properties:
                links:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                      relationship:
                        type: string
                      metadata:
                        nullable: true
                    required:
                      - id
              required:
                - links
      responses:
        "200":
          description: Update count
          content:
            application/json:
              schema:
                type: object
                properties:
                  updated:
                    type: number
                required:
                  - updated
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/entity-links/{linkId}:
    patch:
      tags:
        - Entity Links
      summary: Update entity link
      security: *a13
      parameters:
        - schema:
            type: string
            description: Entity link ID
          required: true
          description: Entity link ID
          name: linkId
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                relationship:
                  type: string
                metadata:
                  nullable: true
      responses:
        "200":
          description: Entity link updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  link:
                    $ref: "#/components/schemas/EntityLink"
                required:
                  - link
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Entity Links
      summary: Delete entity link
      security: *a13
      parameters:
        - schema:
            type: string
            description: Entity link ID
          required: true
          description: Entity link ID
          name: linkId
          in: path
      responses:
        "200":
          description: Entity link deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/entity-objects/{id}:
    get:
      tags:
        - Entity Objects
      summary: Resolve an entity_object by UUID — canonical_type, source_url, title
      description: 'Used by the per-quote source rendering primitive (BRI-3199 / M7.3). Quotes carry an
        `anchor.entity_object_id`; the UI resolves it through this endpoint to render `[icon] [label] "text" →
        source_url`. Org-scoped: returns 404 for objects in other orgs.'
      security:
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: Entity object UUID
          required: true
          description: Entity object UUID
          name: id
          in: path
      responses:
        "200":
          description: Entity object
          content:
            application/json:
              schema:
                type: object
                properties:
                  entity_object:
                    $ref: "#/components/schemas/EntityObject"
                required:
                  - entity_object
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/product-context:
    get:
      tags:
        - Product Context
      summary: Get product context config
      security: &a14
        - ApiKeyAuth: []
      responses:
        "200":
          description: Product context configuration
          content:
            application/json:
              schema:
                type: object
                properties:
                  config:
                    $ref: "#/components/schemas/ProductContextConfig"
                  updated_at:
                    type: string
                    nullable: true
                  valid:
                    type: boolean
                  validation_errors:
                    type: object
                    properties:
                      formErrors:
                        type: array
                        items:
                          type: string
                      fieldErrors:
                        type: object
                        additionalProperties:
                          type: array
                          items:
                            type: string
                    required:
                      - formErrors
                      - fieldErrors
                  product_address_unavailable:
                    type: boolean
                    description: The product address could not be read for this response. An absent config.productAddress means unknown, not
                      unset — a client writing this response back must omit the field.
                required:
                  - config
                  - updated_at
                  - valid
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    put:
      tags:
        - Product Context
      summary: Update product context
      security: *a14
      requestBody:
        description: Product context config to set
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductContextConfig"
      responses:
        "200":
          description: Updated product context
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  config:
                    $ref: "#/components/schemas/ProductContextConfig"
                  updated_at:
                    type: string
                  product_address_unavailable:
                    type: boolean
                    description: "Same meaning as on the GET: the address could not be read while serving this response, so an absent
                      config.productAddress is unknown rather than unset."
                required:
                  - success
                  - config
                  - updated_at
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/product-context/current-state:
    get:
      tags:
        - Product Context
      summary: Get current state analysis
      security: *a14
      responses:
        "200":
          description: Current state analysis
          content:
            application/json:
              schema:
                type: object
                properties: {}
                additionalProperties:
                  nullable: true
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Product Context
      summary: Trigger state analysis
      security: *a14
      responses:
        "200":
          description: State analysis triggered
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/product-context/inference-results:
    get:
      tags:
        - Product Context
      summary: Get inference results
      security: *a14
      responses:
        "200":
          description: Inference results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      properties: {}
                      additionalProperties:
                        nullable: true
                required:
                  - results
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Product Context
      summary: Clear inference results
      security: *a14
      requestBody:
        description: Optional filter and feedback fields
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InferenceResultsDeleteBody"
      responses:
        "200":
          description: Inference results cleared
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted:
                    anyOf:
                      - type: number
                      - type: string
                        enum:
                          - all
                required:
                  - deleted
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/velocity:
    get:
      tags:
        - Velocity
      summary: Get velocity metrics
      security: *a14
      responses:
        "200":
          description: Velocity metrics
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VelocityMetricsResponse"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/product-context/velocity:
    get:
      tags:
        - Velocity
      summary: Get velocity metrics (deprecated alias)
      deprecated: true
      security: *a14
      responses:
        "200":
          description: Velocity metrics
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VelocityMetricsResponse"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/org/mcp-servers:
    get:
      tags:
        - MCP Servers
      summary: List MCP servers
      security: &a15
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: boolean
            nullable: true
            default: false
          required: false
          name: include_disabled
          in: query
        - schema:
            type: boolean
            nullable: true
            default: false
          required: false
          name: managed_only
          in: query
        - schema:
            type: string
            enum:
              - SUPABASE
              - SNOWFLAKE
              - BIGQUERY
              - POSTGRES
          required: false
          name: managed_provider
          in: query
      responses:
        "200":
          description: MCP server list
          content:
            application/json:
              schema:
                type: object
                properties:
                  servers:
                    type: array
                    items:
                      $ref: "#/components/schemas/McpServer"
                required:
                  - servers
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - MCP Servers
      summary: Create MCP server
      security: *a15
      requestBody:
        description: MCP server to create
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 100
                description:
                  type: string
                  maxLength: 500
                endpoint:
                  type: string
                  minLength: 1
                  format: uri
                auth_type:
                  type: string
                  enum:
                    - api_key
                    - bearer
                    - basic
                    - mtls
                    - none
                    - oauth
                auth_config:
                  type: object
                  additionalProperties:
                    nullable: true
                credentials:
                  type: object
                  properties:
                    api_key:
                      type: string
                      minLength: 1
                    token:
                      type: string
                      minLength: 1
                    username:
                      type: string
                      minLength: 1
                    password:
                      type: string
                      minLength: 1
                    client_cert:
                      type: string
                      minLength: 1
                    client_key:
                      type: string
                      minLength: 1
                oauth_advanced:
                  type: object
                  properties:
                    client_id:
                      type: string
                      minLength: 1
                    client_secret:
                      type: string
                      minLength: 1
                    scopes:
                      type: array
                      items:
                        type: string
                        minLength: 1
                timeout_ms:
                  type: integer
                  minimum: 1000
                  maximum: 300000
                max_retries:
                  type: integer
                  minimum: 0
                  maximum: 10
                rate_limit_per_minute:
                  type: integer
                  minimum: 1
                  maximum: 1000
                rate_limit_per_hour:
                  type: integer
                  minimum: 1
                  maximum: 10000
              required:
                - name
                - endpoint
                - auth_type
      responses:
        "201":
          description: Created MCP server
          content:
            application/json:
              schema:
                type: object
                properties:
                  server:
                    $ref: "#/components/schemas/McpServer"
                required:
                  - server
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/org/mcp-servers/{id}:
    get:
      tags:
        - MCP Servers
      summary: Get MCP server
      security: *a15
      parameters:
        - schema:
            type: string
            description: MCP server ID
          required: true
          description: MCP server ID
          name: id
          in: path
      responses:
        "200":
          description: MCP server details
          content:
            application/json:
              schema:
                type: object
                properties:
                  server:
                    $ref: "#/components/schemas/McpServer"
                required:
                  - server
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - MCP Servers
      summary: Update MCP server
      security: *a15
      parameters:
        - schema:
            type: string
            description: MCP server ID
          required: true
          description: MCP server ID
          name: id
          in: path
      requestBody:
        description: Fields to update
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 100
                description:
                  type: string
                  nullable: true
                  maxLength: 500
                endpoint:
                  type: string
                  format: uri
                auth_type:
                  type: string
                  enum:
                    - api_key
                    - bearer
                    - basic
                    - mtls
                    - none
                    - oauth
                auth_config:
                  type: object
                  additionalProperties:
                    nullable: true
                credentials:
                  type: object
                  nullable: true
                  properties:
                    api_key:
                      type: string
                      minLength: 1
                    token:
                      type: string
                      minLength: 1
                    username:
                      type: string
                      minLength: 1
                    password:
                      type: string
                      minLength: 1
                    client_cert:
                      type: string
                      minLength: 1
                    client_key:
                      type: string
                      minLength: 1
                timeout_ms:
                  type: integer
                  minimum: 1000
                  maximum: 300000
                max_retries:
                  type: integer
                  minimum: 0
                  maximum: 10
                enabled:
                  type: boolean
                rate_limit_per_minute:
                  type: integer
                  minimum: 1
                  maximum: 1000
                rate_limit_per_hour:
                  type: integer
                  nullable: true
                  minimum: 1
                  maximum: 10000
      responses:
        "200":
          description: Updated MCP server
          content:
            application/json:
              schema:
                type: object
                properties:
                  server:
                    $ref: "#/components/schemas/McpServer"
                required:
                  - server
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - MCP Servers
      summary: Delete MCP server
      security: *a15
      parameters:
        - schema:
            type: string
            description: MCP server ID
          required: true
          description: MCP server ID
          name: id
          in: path
      responses:
        "200":
          description: MCP server deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/org/mcp-servers/{id}/audit-logs:
    get:
      tags:
        - MCP Servers
      summary: Get audit logs
      security: *a15
      parameters:
        - schema:
            type: string
            description: MCP server ID
          required: true
          description: MCP server ID
          name: id
          in: path
      responses:
        "200":
          description: Audit log entries
          content:
            application/json:
              schema:
                type: object
                properties:
                  logs:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        action:
                          type: string
                        actor_id:
                          type: string
                          nullable: true
                        actor_email:
                          type: string
                          nullable: true
                        timestamp:
                          type: string
                        details:
                          type: object
                          nullable: true
                          additionalProperties:
                            nullable: true
                      required:
                        - id
                        - action
                        - actor_id
                        - timestamp
                required:
                  - logs
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/me:
    get:
      tags:
        - Me
      summary: Get signed-in user profile
      description: Returns the signed-in user's id, firstName, account-creation timestamp, and last-seen timestamp. Used by
        the chrome extension to render the personalized greeting matrix.
      security: &a16
        - ApiKeyAuth: []
        - ClerkSession: []
      responses:
        "200":
          description: Signed-in user profile
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MeResponse"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Me
      summary: Update last-seen timestamp
      description: Writes lastSeenAt to Clerk unsafeMetadata. Shared recency clock with Brief web.
      security: *a16
      requestBody:
        description: Last-seen update
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PatchMeBody"
      responses:
        "200":
          description: Update applied
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PatchMeResponse"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/lite/reports:
    get:
      tags:
        - Lite
      summary: List the org's Brief Lite reports (most-recent-first, bounded)
      security:
        - ApiKeyAuth: []
      responses:
        "200":
          description: The org's lite reports for the post-claim landing
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        slug:
                          type: string
                          nullable: true
                        title:
                          type: string
                        created_at:
                          type: string
                          nullable: true
                        report_type:
                          type: string
                        report_type_label:
                          type: string
                        executive_summary:
                          type: string
                      required:
                        - id
                        - slug
                        - title
                        - created_at
                        - report_type
                        - report_type_label
                        - executive_summary
                  total_count:
                    type: number
                  truncated:
                    type: boolean
                required:
                  - items
                  - total_count
                  - truncated
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/workspaces:
    get:
      tags:
        - Workspaces
      summary: List available workspaces
      security:
        - ApiKeyAuth: []
      responses:
        "200":
          description: Workspaces available to the authenticated user
          content:
            application/json:
              schema:
                type: object
                properties:
                  workspaces:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        role:
                          type: string
                          nullable: true
                        active:
                          type: boolean
                      required:
                        - id
                        - name
                        - role
                        - active
                required:
                  - workspaces
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/feedback:
    post:
      tags:
        - Feedback
      summary: Send feedback to Brief support
      description: Sends a support request, bug report, feature request, or general feedback to Brief support and copies the
        authenticated user email.
      security:
        - ApiKeyAuth: []
        - ClerkSession: []
      requestBody:
        description: Feedback submission
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  enum:
                    - support
                    - bug
                    - feature
                    - general
                title:
                  type: string
                  minLength: 1
                  maxLength: 160
                  pattern: ^[^\r\n]+$
                description:
                  type: string
                  minLength: 1
                  maxLength: 10000
              required:
                - category
                - title
                - description
      responses:
        "200":
          description: Feedback sent
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  submissionId:
                    type: string
                    format: uuid
                  copiedTo:
                    type: string
                    format: email
                required:
                  - success
                  - submissionId
                  - copiedTo
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Rate limited. A Retry-After header (seconds) is set when retry_after is present.
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    properties:
                      error:
                        type: string
                      code:
                        type: string
                        enum:
                          - rate_limited
                      retry_after:
                        type: integer
                    required:
                      - error
                      - code
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "503":
          description: Organization membership could not be verified. A Retry-After header (seconds) is set.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/sources/sync:
    post:
      summary: Refresh a surface's sources, then run its agents
      description: Dispatches source ingestion for the bindings behind one product surface and runs that surface's agent chain
        once the sources reach a terminal state. Bindings pass isEmittableBinding and then
        filterSourceRunnerAdmittedBindings, the same admission call the daily cron uses; refused bindings are reported
        in excludedSources rather than dispatched. Repeated presses inside dedupeWindowSeconds collapse onto the same
        runs.
      security:
        - ApiKeyAuth: []
        - ClerkSession: []
      requestBody:
        description: Surface to refresh
        content:
          application/json:
            schema:
              type: object
              properties:
                scope:
                  type: string
                  enum:
                    - features
                    - product-context
                    - market
                    - user-intelligence
              required:
                - scope
      responses:
        "200":
          description: Sync dispatched
          content:
            application/json:
              schema:
                type: object
                properties:
                  started:
                    type: boolean
                  runs:
                    type: array
                    items:
                      type: object
                      properties:
                        runId:
                          type: string
                          format: uuid
                        adapterId:
                          type: string
                        domain:
                          type: string
                        sourceBindingId:
                          type: string
                        sourceLabel:
                          type: string
                      required:
                        - runId
                        - adapterId
                        - domain
                        - sourceBindingId
                        - sourceLabel
                  excludedSources:
                    type: array
                    items:
                      type: object
                      properties:
                        adapterId:
                          type: string
                        domain:
                          type: string
                        sourceBindingId:
                          type: string
                        sourceLabel:
                          type: string
                      required:
                        - adapterId
                        - domain
                        - sourceBindingId
                        - sourceLabel
                  excludedCount:
                    type: integer
                    minimum: 0
                  dedupeWindowSeconds:
                    type: integer
                    minimum: 0
                  correlationId:
                    type: string
                    format: uuid
                  bindingRefreshFailed:
                    type: boolean
                  wakeupSuppressedForMs:
                    type: number
                required:
                  - started
                  - runs
                  - excludedSources
                  - excludedCount
                  - dedupeWindowSeconds
                  - correlationId
                  - bindingRefreshFailed
                  - wakeupSuppressedForMs
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/sources/sync/cancel:
    post:
      summary: Stop a sync in progress
      description: Retires the server-side coordinator as well as the caller's polling, so the agent chain stops rather than
        only the page watching it. The organization comes from the session, so a correlation id cannot stop another
        org's sync.
      security:
        - ApiKeyAuth: []
        - ClerkSession: []
      requestBody:
        description: The correlationId returned by the sync response
        content:
          application/json:
            schema:
              type: object
              properties:
                correlationId:
                  type: string
                  format: uuid
              required:
                - correlationId
      responses:
        "200":
          description: Cancel accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  cancelled:
                    type: boolean
                    enum:
                      - true
                required:
                  - cancelled
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/chat:
    post:
      tags:
        - Chat
      summary: Send a chat message
      description: "Starts a chat turn. By default the response is a server-sent event stream of the turn. When the request
        carries `x-brief-async-dispatch: 1` the server answers with a JSON acknowledgement and the caller reads the
        answer from `GET /api/v1/chat/results/{chatTurnId}`."
      security: &a17
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            enum:
              - "1"
          required: false
          name: x-brief-async-dispatch
          in: header
        - schema:
            type: string
          required: false
          name: x-chat-turn-id
          in: header
      requestBody:
        description: Chat turn request
        content:
          application/json:
            schema:
              type: object
              properties:
                messages:
                  type: array
                  items:
                    nullable: true
                  maxItems: 100
                modelId:
                  type: string
                conversationId:
                  type: string
                conversationIdIsClaimed:
                  type: boolean
                presetId:
                  type: string
                  nullable: true
                contextDocIds:
                  type: array
                  items:
                    type: string
                    format: uuid
                attachedDocIds:
                  type: array
                  items:
                    type: string
                    format: uuid
                contextEntityRefs:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                      entityType:
                        type: string
                        enum:
                          - decision
                          - feature
                          - persona
                          - research_signal
                          - competitor
                      title:
                        type: string
                    required:
                      - id
                      - entityType
                      - title
                folderId:
                  type: string
                  format: uuid
                currentPage:
                  type: object
                  properties:
                    type:
                      type: string
                      enum:
                        - strategic-dashboard
                        - decision
                        - document
                        - product-context
                        - features
                        - integrations
                        - chat
                        - empty
                        - folder
                        - user-intelligence
                        - users
                        - market
                        - agent
                        - search
                    id:
                      type: string
                    title:
                      type: string
                    meta:
                      type: object
                      properties:
                        folderId:
                          type: string
                          nullable: true
                        documentId:
                          type: string
                          nullable: true
                        conversationId:
                          type: string
                          nullable: true
                        isPage:
                          type: boolean
                        integrationsTab:
                          type: string
                          enum:
                            - connect-tools
                            - install-brief
                        folderPath:
                          type: string
                          nullable: true
                        activeTab:
                          type: string
                        artifactSource:
                          type: string
                        artifactType:
                          type: string
                        agentName:
                          type: string
                          minLength: 1
                          maxLength: 80
                          pattern: ^[a-z0-9-]+$
                      additionalProperties: false
                  required:
                    - type
                lastViewedPage:
                  type: object
                  properties:
                    type:
                      type: string
                      enum:
                        - strategic-dashboard
                        - decision
                        - document
                        - product-context
                        - features
                        - integrations
                        - chat
                        - empty
                        - folder
                        - user-intelligence
                        - users
                        - market
                        - agent
                        - search
                    id:
                      type: string
                    title:
                      type: string
                    meta:
                      type: object
                      properties:
                        folderId:
                          type: string
                          nullable: true
                        documentId:
                          type: string
                          nullable: true
                        conversationId:
                          type: string
                          nullable: true
                        isPage:
                          type: boolean
                        integrationsTab:
                          type: string
                          enum:
                            - connect-tools
                            - install-brief
                        folderPath:
                          type: string
                          nullable: true
                        activeTab:
                          type: string
                        artifactSource:
                          type: string
                        artifactType:
                          type: string
                        agentName:
                          type: string
                          minLength: 1
                          maxLength: 80
                          pattern: ^[a-z0-9-]+$
                      additionalProperties: false
                  required:
                    - type
                activePreview:
                  type: object
                  properties:
                    type:
                      type: string
                    id:
                      type: string
                    title:
                      type: string
                      nullable: true
                  required:
                    - type
                    - id
                    - title
                contextUrl:
                  type: string
                  format: uri
                externalPage:
                  type: object
                  properties:
                    url:
                      type: string
                      format: uri
                    title:
                      type: string
                      maxLength: 500
                    contentSelection:
                      type: string
                      maxLength: 50000
                    contentText:
                      type: string
                      maxLength: 50000
                    contentScreenshot:
                      type: string
                      maxLength: 500000
                    truncated:
                      type: boolean
                    totalChars:
                      type: integer
                      minimum: 0
                    capturedAt:
                      type: string
                      format: date-time
                    source:
                      type: string
                      enum:
                        - selection
                        - full_page
                        - screenshot
                  required:
                    - url
                    - title
                    - capturedAt
                    - source
                digestDate:
                  type: string
                  nullable: true
                  pattern: ^\d{4}-\d{2}-\d{2}$
                digestType:
                  type: string
                  nullable: true
                  enum:
                    - daily
                    - weekly
                    - strategic
                    - null
                channel:
                  type: string
                  enum:
                    - slack_dm
                    - slack_channel
                    - teams_dm
                    - teams_channel
                    - web
                    - extension
                    - voice
                    - mobile
                    - mcp
                    - cli
                    - coding_agent
                    - email
                    - terminal
                    - terminal_agent
                rawFiles:
                  type: array
                  items:
                    type: object
                    properties:
                      base64:
                        type: string
                        maxLength: 2097152
                      filename:
                        type: string
                        maxLength: 255
                      mimetype:
                        type: string
                        maxLength: 100
                    required:
                      - base64
                      - filename
                      - mimetype
                  maxItems: 10
                fileRefs:
                  type: array
                  items:
                    type: object
                    properties:
                      uploadId:
                        type: string
                        format: uuid
                      storagePath:
                        type: string
                        maxLength: 512
                      filename:
                        type: string
                        maxLength: 255
                      mimetype:
                        type: string
                        maxLength: 100
                      isImage:
                        type: boolean
                    required:
                      - storagePath
                      - filename
                      - mimetype
                      - isImage
                  maxItems: 10
                recentlyCompletedAgents:
                  type: array
                  items:
                    type: string
                    maxLength: 100
                    pattern: ^[a-zA-Z0-9_]+$
                  maxItems: 10
                recentlyConnectedIntegrations:
                  type: array
                  items:
                    type: string
                    maxLength: 100
                    pattern: ^[a-zA-Z0-9_]+$
                  maxItems: 10
                stagedIntegrations:
                  type: array
                  items:
                    type: string
                    maxLength: 100
                    pattern: ^[a-zA-Z0-9_]+$
                  maxItems: 50
                stagedIntegrationsSeeded:
                  type: boolean
                inviteAction:
                  type: string
                  enum:
                    - sent
                    - skipped
                slackUserId:
                  type: string
                  pattern: ^[UW][A-Z0-9]{1,31}$
                slackBotUserId:
                  type: string
                  pattern: ^[UW][A-Z0-9]{1,31}$
                slackTeamId:
                  type: string
                  pattern: ^T[A-Z0-9]{1,31}$
                slackChannel:
                  type: object
                  properties:
                    id:
                      type: string
                      pattern: ^[CG][A-Z0-9]{1,31}$
                    name:
                      type: string
                      minLength: 1
                      maxLength: 80
                      pattern: ^[^\s<>]+$
                  required:
                    - id
                hasThreadContext:
                  type: boolean
                threadContextText:
                  type: string
                  maxLength: 100000
                slackDeliveryIntent:
                  type: object
                  properties:
                    eventId:
                      type: string
                      minLength: 1
                      maxLength: 255
                    channelMode:
                      type: string
                      enum:
                        - slack_dm
                        - slack_channel
                    teamId:
                      type: string
                      minLength: 1
                      maxLength: 64
                    channelId:
                      type: string
                      minLength: 1
                      maxLength: 64
                    threadTs:
                      type: string
                      minLength: 1
                      maxLength: 64
                    acknowledgementTs:
                      type: string
                      minLength: 1
                      maxLength: 64
                    slackUserId:
                      type: string
                      minLength: 1
                      maxLength: 64
                    slackBotUserId:
                      type: string
                      minLength: 1
                      maxLength: 64
                    slackUserEmail:
                      type: string
                      maxLength: 320
                    slackUserName:
                      type: string
                      maxLength: 255
                    threadSessionId:
                      type: string
                      minLength: 1
                      maxLength: 255
                    queueConversationId:
                      type: string
                      minLength: 1
                      maxLength: 255
                    queueMessageId:
                      type: string
                      minLength: 1
                      maxLength: 255
                    originalMessageText:
                      type: string
                      maxLength: 100000
                    hasBriefAccount:
                      type: boolean
                    startedAtMs:
                      type: integer
                      minimum: 0
                  required:
                    - eventId
                    - channelMode
                    - teamId
                    - channelId
                    - slackUserId
                    - originalMessageText
                    - hasBriefAccount
                    - startedAtMs
                  additionalProperties: false
                clientTools:
                  type: array
                  items:
                    type: string
                    enum:
                      - read_local_file
                      - list_local_files
                      - search_local_files
                      - consult_local_agent
                      - list_local_agents
                      - message_local_agent
                  maxItems: 8
                localContext:
                  type: object
                  properties:
                    repo:
                      type: string
                      maxLength: 120
                    branch:
                      type: string
                      nullable: true
                      maxLength: 200
                    ticket:
                      type: string
                      nullable: true
                      pattern: ^[A-Z][A-Z0-9]{1,9}-\d{1,7}$
                    headSha:
                      type: string
                      nullable: true
                      maxLength: 64
                    status:
                      type: string
                      maxLength: 4096
                    diffStat:
                      type: string
                      maxLength: 4096
                    changedFiles:
                      type: array
                      items:
                        type: string
                        maxLength: 512
                      maxItems: 100
                    recentCommits:
                      type: array
                      items:
                        type: string
                        maxLength: 200
                      maxItems: 20
                    mentionedFiles:
                      type: array
                      items:
                        type: string
                        maxLength: 512
                      maxItems: 20
                    generatedAt:
                      type: string
                      format: date-time
                  required:
                    - repo
                    - branch
                    - ticket
                    - headSha
                    - status
                    - diffStat
                    - changedFiles
                    - recentCommits
                    - generatedAt
                  additionalProperties: false
                worktreeBehavior:
                  type: string
                  enum:
                    - gap_read
                    - pr_review
                    - directive
                addressedTo:
                  type: object
                  properties:
                    ticket:
                      type: string
                      pattern: ^[A-Z][A-Z0-9]{1,9}-\d{1,7}$
                    sessionName:
                      type: string
                      maxLength: 80
                  required:
                    - ticket
                  additionalProperties: false
                agentIntent:
                  type: string
                  enum:
                    - question
                    - status
                    - diff_summary
                    - consult
                clientTelemetry:
                  type: object
                  properties:
                    agentSessionsPresent:
                      type: integer
                      minimum: 0
                      maximum: 1000
                    resumed:
                      type: boolean
                  required:
                    - agentSessionsPresent
                    - resumed
                  additionalProperties: false
              required:
                - messages
      responses:
        "200":
          description: Event stream of the turn, or the dispatch acknowledgement when async dispatch was requested
          content:
            text/event-stream:
              schema:
                type: string
            application/json:
              schema:
                type: object
                properties:
                  chatTurnId:
                    type: string
                  turnId:
                    type: string
                  conversationId:
                    type: string
                  turn:
                    $ref: "#/components/schemas/ChatTurnState"
                required:
                  - chatTurnId
                  - turnId
                  - conversationId
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Rate limited or out of credits
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ErrorResponse"
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/chat/files:
    post:
      tags:
        - Chat
      summary: Upload a chat attachment
      security: *a17
      requestBody:
        description: The file to attach
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                uploadRequestId:
                  type: string
                  format: uuid
              required:
                - file
      responses:
        "201":
          description: Stored attachment, ready to reference from a chat turn
          content:
            application/json:
              schema:
                type: object
                properties:
                  uploadId:
                    type: string
                  storagePath:
                    type: string
                  filename:
                    type: string
                  mimetype:
                    type: string
                  isImage:
                    type: boolean
                required:
                  - uploadId
                  - storagePath
                  - filename
                  - mimetype
                  - isImage
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Rate limited
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ErrorResponse"
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/chat/results/{chatTurnId}:
    get:
      tags:
        - Chat
      summary: Read the result of a chat turn
      description: Poll this after an async dispatch. Answers 202 while the turn is processing and 200 once it is complete.
      security: *a17
      parameters:
        - schema:
            type: string
            description: Chat turn ID
          required: true
          description: Chat turn ID
          name: chatTurnId
          in: path
        - schema:
            type: string
            format: uuid
          required: false
          name: conversationId
          in: query
      responses:
        "200":
          description: Completed turn
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - processing
                      - complete
                  phase:
                    type: string
                    enum:
                      - processing
                      - complete
                  requestId:
                    type: string
                  turn:
                    $ref: "#/components/schemas/ChatTurnState"
                  conversationId:
                    type: string
                  text:
                    type: string
                  toolEvents:
                    type: array
                    items:
                      type: object
                      properties:
                        toolName:
                          type: string
                        output:
                          nullable: true
                      required:
                        - toolName
                  approvalRequests:
                    type: array
                    items:
                      type: object
                      properties:
                        approvalId:
                          type: string
                        toolCallId:
                          type: string
                        toolName:
                          type: string
                        input:
                          nullable: true
                      required:
                        - toolCallId
                        - toolName
                  decisionIds:
                    type: array
                    items:
                      type: string
                  documentRetrievalSignal:
                    type: string
                    enum:
                      - weak-or-empty
                      - strong
                  documentRetrievalAmbiguous:
                    type: boolean
                  streamError:
                    type: string
                  pointer:
                    type: boolean
                  turnId:
                    type: string
                  truncated:
                    type: boolean
                required:
                  - status
                  - phase
                  - requestId
        "202":
          description: Turn is still processing
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - processing
                      - complete
                  phase:
                    type: string
                    enum:
                      - processing
                      - complete
                  requestId:
                    type: string
                  turn:
                    $ref: "#/components/schemas/ChatTurnState"
                  conversationId:
                    type: string
                  text:
                    type: string
                  toolEvents:
                    type: array
                    items:
                      type: object
                      properties:
                        toolName:
                          type: string
                        output:
                          nullable: true
                      required:
                        - toolName
                  approvalRequests:
                    type: array
                    items:
                      type: object
                      properties:
                        approvalId:
                          type: string
                        toolCallId:
                          type: string
                        toolName:
                          type: string
                        input:
                          nullable: true
                      required:
                        - toolCallId
                        - toolName
                  decisionIds:
                    type: array
                    items:
                      type: string
                  documentRetrievalSignal:
                    type: string
                    enum:
                      - weak-or-empty
                      - strong
                  documentRetrievalAmbiguous:
                    type: boolean
                  streamError:
                    type: string
                  pointer:
                    type: boolean
                  turnId:
                    type: string
                  truncated:
                    type: boolean
                required:
                  - status
                  - phase
                  - requestId
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/chat/stop:
    post:
      tags:
        - Chat
      summary: Stop an active chat turn
      security: *a17
      requestBody:
        description: Turn to stop
        content:
          application/json:
            schema:
              type: object
              properties:
                turnId:
                  type: string
              required:
                - turnId
      responses:
        "204":
          description: Stop requested
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: The turn is not ready or is no longer active
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "503":
          description: Unable to stop the active turn
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/ask/fast:
    post:
      tags:
        - Chat
      summary: Ask a question in fast mode
      description: Answers from Brief's context without tools. Read-scoped credentials may call it.
      security: *a17
      requestBody:
        description: Question to answer
        content:
          application/json:
            schema:
              type: object
              properties:
                question:
                  type: string
                  minLength: 1
                context:
                  type: string
              required:
                - question
      responses:
        "200":
          description: Answer
          content:
            application/json:
              schema:
                type: object
                properties:
                  answer:
                    type: string
                  metadata:
                    type: object
                    properties:
                      mode:
                        type: string
                        enum:
                          - advise
                          - check
                          - fast
                      conversation_id:
                        type: string
                      tools_used:
                        type: array
                        items:
                          type: string
                      decisions_referenced:
                        type: array
                        items:
                          type: string
                      confidence:
                        type: string
                        enum:
                          - high
                          - medium
                          - low
                      confidence_reason:
                        type: string
                      suggested_actions:
                        type: array
                        items:
                          type: string
                      confirmation_status:
                        type: string
                      lifecycle_state:
                        type: string
                      rate_limit_remaining:
                        type: number
                      powered_by:
                        type: string
                      onboarding:
                        type: object
                        additionalProperties:
                          nullable: true
                    required:
                      - mode
                      - tools_used
                      - decisions_referenced
                      - confidence
                      - confidence_reason
                      - suggested_actions
                      - powered_by
                  confirmation_required:
                    type: object
                    properties:
                      actions:
                        type: array
                        items:
                          type: object
                          properties:
                            type:
                              type: string
                              enum:
                                - create_decision
                            tool:
                              type: string
                              enum:
                                - brief_execute_operation
                            payload:
                              type: object
                              properties:
                                operation:
                                  type: string
                                parameters:
                                  type: object
                                  additionalProperties:
                                    nullable: true
                              required:
                                - operation
                                - parameters
                            message:
                              type: string
                          required:
                            - type
                            - tool
                            - payload
                            - message
                    required:
                      - actions
                  formatted:
                    type: string
                required:
                  - answer
                  - metadata
                  - formatted
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Out of credits, rate limited or provider at its usage limit
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    properties:
                      success:
                        type: boolean
                        enum:
                          - false
                      error:
                        type: object
                        properties:
                          code:
                            type: string
                          message:
                            type: string
                          suggestion:
                            type: string
                          details:
                            type: object
                            additionalProperties:
                              nullable: true
                          docs:
                            type: string
                          retry_after:
                            type: number
                        required:
                          - code
                          - message
                    required:
                      - error
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error or fast ask failure
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ErrorResponse"
                  - type: object
                    properties:
                      success:
                        type: boolean
                        enum:
                          - false
                      error:
                        type: object
                        properties:
                          code:
                            type: string
                          message:
                            type: string
                          suggestion:
                            type: string
                          details:
                            type: object
                            additionalProperties:
                              nullable: true
                          docs:
                            type: string
                          retry_after:
                            type: number
                        required:
                          - code
                          - message
                    required:
                      - error
        "502":
          description: Fast ask failed
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      suggestion:
                        type: string
                      details:
                        type: object
                        additionalProperties:
                          nullable: true
                      docs:
                        type: string
                      retry_after:
                        type: number
                    required:
                      - code
                      - message
                required:
                  - error
        "504":
          description: Fast ask timed out
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      suggestion:
                        type: string
                      details:
                        type: object
                        additionalProperties:
                          nullable: true
                      docs:
                        type: string
                      retry_after:
                        type: number
                    required:
                      - code
                      - message
                required:
                  - error
  /api/v1/presets:
    get:
      tags:
        - Chat
      summary: List chat presets
      description: The full preset catalog plus the caller's curation context.
      security: *a17
      responses:
        "200":
          description: Preset catalog
          content:
            application/json:
              schema:
                type: object
                properties:
                  presets:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        label:
                          type: string
                        description:
                          type: string
                        category:
                          type: string
                        sendText:
                          type: string
                        template:
                          type: string
                        pages:
                          type: array
                          items:
                            type: string
                        priority:
                          type: number
                        minTenureDays:
                          type: number
                        maxTenureDays:
                          type: number
                        requiresData:
                          type: array
                          items:
                            type: string
                        metadata:
                          type: object
                          additionalProperties:
                            nullable: true
                      required:
                        - id
                        - label
                  context:
                    type: object
                    properties:
                      tenureDays:
                        type: number
                      hasIntegrations:
                        type: boolean
                      hasDecisions:
                        type: boolean
                      hasIntegrationIssues:
                        type: boolean
                      lastSeenDays:
                        type: number
                    required:
                      - tenureDays
                      - hasIntegrations
                      - hasDecisions
                      - lastSeenDays
                  version:
                    type: string
                required:
                  - presets
                  - context
                  - version
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/sub-agents/{id}:
    get:
      tags:
        - Chat
      summary: Get the status of a sub-agent
      security: &a18
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: Sub-agent ID
          required: true
          description: Sub-agent ID
          name: id
          in: path
      responses:
        "200":
          description: Sub-agent status
          content:
            application/json:
              schema:
                type: object
                properties:
                  agent_id:
                    type: string
                  task:
                    type: string
                  status:
                    type: string
                    enum:
                      - queued
                      - running
                      - completed
                      - failed
                      - cancelled
                  progress:
                    type: array
                    items:
                      type: object
                      properties:
                        timestamp:
                          type: string
                        message:
                          type: string
                        tool_used:
                          type: string
                        percentage:
                          type: number
                      required:
                        - timestamp
                        - message
                  result:
                    type: string
                    nullable: true
                  error:
                    type: string
                    nullable: true
                  created_at:
                    type: string
                  started_at:
                    type: string
                    nullable: true
                  completed_at:
                    type: string
                    nullable: true
                  timeout_at:
                    type: string
                    nullable: true
                  group_id:
                    type: string
                    nullable: true
                  metadata:
                    type: object
                    nullable: true
                    additionalProperties:
                      nullable: true
                required:
                  - agent_id
                  - task
                  - status
                  - progress
                  - result
                  - error
                  - created_at
                  - started_at
                  - completed_at
                  - timeout_at
                  - group_id
                  - metadata
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/artifacts/save:
    post:
      tags:
        - Artifacts
      summary: Save an artifact as a document
      description: Send `source`, `contentType`, `title` and `folderId` to save inline artifact source as a new document, or
        `artifactId` and `folderId` to move an existing ephemeral artifact into a folder.
      security: *a18
      requestBody:
        description: Artifact to save
        content:
          application/json:
            schema:
              anyOf:
                - type: object
                  properties:
                    source:
                      type: string
                      minLength: 1
                    contentType:
                      type: string
                      enum:
                        - mermaid
                        - wiremd
                        - widget
                        - chart
                    title:
                      type: string
                      minLength: 1
                    folderId:
                      type: string
                      format: uuid
                  required:
                    - source
                    - contentType
                    - title
                    - folderId
                - type: object
                  properties:
                    artifactId:
                      type: string
                      format: uuid
                    folderId:
                      type: string
                      format: uuid
                  required:
                    - artifactId
                    - folderId
      responses:
        "200":
          description: Saved document
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  title:
                    type: string
                  category:
                    type: string
                    nullable: true
                  artifactType:
                    type: string
                    nullable: true
                  url:
                    type: string
                required:
                  - id
                  - title
                  - category
                  - artifactType
                  - url
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: The destination is a skills folder and a skill with the artifact's name already exists there
            (`active_skill_name_already_exists`)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/artifacts/render-preview:
    post:
      tags:
        - Artifacts
      summary: Render a widget or chart to a PNG
      description: Read-scoped credentials may call it. Nothing is stored.
      security: *a18
      requestBody:
        description: Source to render
        content:
          application/json:
            schema:
              type: object
              properties:
                source:
                  type: string
                  minLength: 1
                  maxLength: 100000
                contentType:
                  type: string
                  enum:
                    - widget
                    - chart
              required:
                - source
                - contentType
      responses:
        "200":
          description: PNG preview
          content:
            image/png:
              schema:
                type: string
                format: binary
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "422":
          description: The preview could not be rendered
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                required:
                  - message
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/voice/token:
    get:
      tags:
        - Voice
      summary: Start a voice session
      description: Returns the voice provider token and the conversation the session writes to. Creates the conversation when
        none is given.
      security: *a18
      parameters:
        - schema:
            type: string
            format: uuid
          required: false
          name: conversationId
          in: query
      responses:
        "200":
          description: Voice session credentials
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversationToken:
                    type: string
                  conversationId:
                    type: string
                  customLlmExtraHeaders:
                    type: object
                    properties:
                      X-Brief-Voice-Token:
                        type: string
                      X-Brief-Org-Id:
                        type: string
                      X-Brief-User-Id:
                        type: string
                    required:
                      - X-Brief-Voice-Token
                      - X-Brief-Org-Id
                      - X-Brief-User-Id
                required:
                  - conversationToken
                  - customLlmExtraHeaders
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Rate limited
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ErrorResponse"
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "502":
          description: The voice service failed or sent an unreadable session
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "503":
          description: No model provider is available
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "504":
          description: The voice service timed out
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/voice/stream/{conversationId}:
    get:
      tags:
        - Voice
      summary: Stream the events of a voice conversation
      description: Server-sent events for the conversation's voice session.
      security: *a18
      parameters:
        - schema:
            type: string
            format: uuid
            description: Conversation ID
          required: true
          description: Conversation ID
          name: conversationId
          in: path
      responses:
        "200":
          description: Event stream
          content:
            text/event-stream:
              schema:
                type: string
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Too many open streams
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ErrorResponse"
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agent/submit:
    post:
      tags:
        - Build Sessions
      summary: Submit a build request
      security: &a19
        - ApiKeyAuth: []
      requestBody:
        description: What to build
        content:
          application/json:
            schema:
              type: object
              properties:
                request:
                  type: string
                  minLength: 10
                  maxLength: 20000
                channel:
                  type: string
                  minLength: 1
                  default: cli
                webhook_url:
                  type: string
              required:
                - request
      responses:
        "200":
          description: Build session created
          content:
            application/json:
              schema:
                type: object
                properties:
                  session_id:
                    type: string
                  webhook_signing_secret:
                    type: string
                required:
                  - session_id
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ErrorResponse"
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agent/sessions/{id}:
    get:
      tags:
        - Build Sessions
      summary: Get a build session
      description: Polled by the CLI during a build. Not rate limited.
      security: *a19
      parameters:
        - schema:
            type: string
            format: uuid
            description: Build session ID
          required: true
          description: Build session ID
          name: id
          in: path
      responses:
        "200":
          description: Build session
          content:
            application/json:
              schema:
                type: object
                properties:
                  session_id:
                    type: string
                  status:
                    type: string
                    enum:
                      - submitted
                      - planning
                      - input_required
                      - awaiting_scan
                      - awaiting_build
                      - building
                      - complete
                      - parked
                      - aborted
                  spec:
                    type: object
                    nullable: true
                    additionalProperties:
                      nullable: true
                  branch:
                    type: string
                    nullable: true
                  pr_url:
                    type: string
                    nullable: true
                  pr_number:
                    type: integer
                    nullable: true
                  files_changed:
                    type: array
                    items:
                      type: string
                  phase_updates:
                    type: array
                    items:
                      type: object
                      properties:
                        timestamp:
                          type: string
                        phase:
                          type: string
                        message:
                          type: string
                        status:
                          type: string
                          enum:
                            - started
                            - completed
                            - failed
                            - skipped
                        duration_ms:
                          type: number
                        metadata:
                          type: object
                          additionalProperties:
                            nullable: true
                      required:
                        - timestamp
                        - phase
                        - message
                        - status
                  created_at:
                    type: string
                  updated_at:
                    type: string
                required:
                  - session_id
                  - status
                  - spec
                  - branch
                  - pr_url
                  - pr_number
                  - files_changed
                  - phase_updates
                  - created_at
                  - updated_at
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agent/submit-answers:
    post:
      tags:
        - Build Sessions
      summary: Answer the planning questions of a build session
      security: *a19
      requestBody:
        description: One answer per question
        content:
          application/json:
            schema:
              type: object
              properties:
                session_id:
                  type: string
                  format: uuid
                answers:
                  type: object
                  additionalProperties:
                    type: string
              required:
                - session_id
                - answers
      responses:
        "200":
          description: Answers accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                required:
                  - ok
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agent/confirm-spec:
    post:
      tags:
        - Build Sessions
      summary: Confirm or reject the spec of a build session
      security: *a19
      requestBody:
        description: Decision on the spec
        content:
          application/json:
            schema:
              type: object
              properties:
                sessionId:
                  type: string
                  minLength: 1
                action:
                  type: string
                  enum:
                    - confirm
                    - reject
              required:
                - sessionId
                - action
      responses:
        "200":
          description: Decision recorded
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                required:
                  - ok
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: The session is not waiting for input
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agent/report-progress:
    post:
      tags:
        - Build Sessions
      summary: Report build progress
      security: *a19
      requestBody:
        description: Progress update
        content:
          application/json:
            schema:
              type: object
              properties:
                task_id:
                  type: string
                  format: uuid
                phase:
                  type: string
                  minLength: 1
                details:
                  type: string
              required:
                - task_id
                - phase
      responses:
        "200":
          description: Progress recorded
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  task_id:
                    type: string
                  phase:
                    type: string
                required:
                  - success
                  - task_id
                  - phase
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/agent/report-completion:
    post:
      tags:
        - Build Sessions
      summary: Report build completion
      security: *a19
      requestBody:
        description: Completion report
        content:
          application/json:
            schema:
              type: object
              properties:
                task_id:
                  type: string
                  format: uuid
                status:
                  type: string
                  enum:
                    - success
                    - failure
                    - partial
                pr_url:
                  type: string
                  format: uri
                branch:
                  type: string
                file_list:
                  type: array
                  items:
                    type: string
                files_changed:
                  type: integer
                  minimum: 0
                test_results:
                  type: string
                failure_reason:
                  type: string
              required:
                - task_id
                - status
      responses:
        "200":
          description: Completion recorded
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  task_id:
                    type: string
                  status:
                    type: string
                    enum:
                      - success
                      - failure
                      - partial
                  scopeCheck:
                    type: object
                    properties:
                      inScope:
                        type: boolean
                      outOfScope:
                        type: array
                        items:
                          type: string
                    required:
                      - inScope
                      - outOfScope
                required:
                  - success
                  - task_id
                  - status
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Concurrent status update
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/daemon/tasks:
    get:
      tags:
        - Daemon
      summary: Claim the next daemon task
      description: Returns at most one pending task, claimed for the caller, plus the sessions that should stop. Needs an
        internal service credential.
      security: &a20
        - ApiKeyAuth: []
      responses:
        "200":
          description: Next task, if any, and stop signals
          content:
            application/json:
              schema:
                type: object
                properties:
                  task:
                    type: object
                    nullable: true
                    properties:
                      type:
                        type: string
                        enum:
                          - scan_codebase
                          - deliver_spec
                      sessionId:
                        type: string
                      payload:
                        type: object
                        additionalProperties:
                          nullable: true
                    required:
                      - type
                      - sessionId
                      - payload
                  stops:
                    type: array
                    items:
                      type: object
                      properties:
                        sessionId:
                          type: string
                        reason:
                          type: string
                          nullable: true
                      required:
                        - sessionId
                        - reason
                required:
                  - task
                  - stops
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/daemon/report:
    post:
      tags:
        - Daemon
      summary: Report a daemon task result
      description: Needs an internal service credential.
      security: *a20
      requestBody:
        description: Task result
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  enum:
                    - scan_result
                    - build_complete
                taskId:
                  type: string
                  format: uuid
                payload:
                  type: object
                  additionalProperties:
                    nullable: true
              required:
                - type
                - taskId
                - payload
      responses:
        "200":
          description: Report accepted or ignored
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    properties:
                      eventId:
                        type: string
                      status:
                        type: string
                        enum:
                          - accepted
                    required:
                      - eventId
                      - status
                  - type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - ignored_missing_session
                          - ignored_terminal
                          - ignored_unclaimed_session
                    required:
                      - status
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/daemon/connect:
    get:
      tags:
        - Daemon
      summary: Open the daemon event stream
      description: Server-sent events. The first event is `connected` with `{ connectionId, status }`; later events are
        `deliver_spec`, `scan_codebase` and `stop`. With `probe=1` the route only checks the credential and answers 204.
        Needs an internal service credential.
      security: *a20
      parameters:
        - schema:
            type: string
          required: false
          name: coding_agent
          in: query
        - schema:
            type: string
            enum:
              - "1"
          required: false
          name: probe
          in: query
      responses:
        "200":
          description: Event stream
          content:
            text/event-stream:
              schema:
                type: string
        "204":
          description: Credential accepted (probe=1)
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/competitors/{competitorId}:
    patch:
      tags:
        - Market
      summary: Change a competitor website
      description: Preserves competitor identity and history, clears crawl comparison state, and queues initial enrichment.
        Unchanged normalized domains are a no-op. Limited to one website change per competitor per hour.
      security: &a21
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
          required: true
          name: competitorId
          in: path
      requestBody:
        description: New competitor website
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                domain:
                  type: string
                  minLength: 1
                  maxLength: 500
              required:
                - domain
              additionalProperties: false
      responses:
        "200":
          description: Saved competitor
          content:
            application/json:
              schema:
                type: object
                properties:
                  competitor:
                    $ref: "#/components/schemas/Competitor"
                  enrichmentStatus:
                    type: string
                    enum:
                      - queued
                      - unconfirmed
                      - skipped
                required:
                  - competitor
                  - enrichmentStatus
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Duplicate domain or concurrent website change
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Website change rate limit exceeded
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ErrorResponse"
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/competitors:
    get:
      tags:
        - Market
      summary: List competitors
      security: *a21
      parameters:
        - schema:
            type: string
          required: false
          name: status
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 200
          required: false
          name: limit
          in: query
      responses:
        "200":
          description: Competitors
          content:
            application/json:
              schema:
                type: object
                properties:
                  competitors:
                    type: array
                    items:
                      $ref: "#/components/schemas/Competitor"
                required:
                  - competitors
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/deals:
    get:
      tags:
        - Market
      summary: List deals
      security: *a21
      parameters:
        - schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 100
          required: false
          name: limit
          in: query
        - schema:
            type: integer
            minimum: 0
            default: 0
          required: false
          name: offset
          in: query
        - schema:
            type: string
          required: false
          name: stage
          in: query
        - schema:
            type: string
          required: false
          name: source
          in: query
        - schema:
            type: string
            format: uuid
            description: Return only this deal
          required: false
          description: Return only this deal
          name: id
          in: query
      responses:
        "200":
          description: Deals
          content:
            application/json:
              schema:
                type: object
                properties:
                  deals:
                    type: array
                    items:
                      $ref: "#/components/schemas/Deal"
                  pagination:
                    type: object
                    properties:
                      total:
                        type: number
                      limit:
                        type: number
                      offset:
                        type: number
                      hasMore:
                        type: boolean
                    required:
                      - total
                      - limit
                      - offset
                      - hasMore
                required:
                  - deals
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/positioning:
    get:
      tags:
        - Market
      summary: Get the organization's positioning
      security: *a21
      responses:
        "200":
          description: Positioning; empty when none is set
          content:
            application/json:
              schema:
                type: object
                properties:
                  positioning:
                    type: object
                    properties:
                      tagline:
                        type: string
                      value_proposition:
                        type: string
                      category:
                        type: string
                      target_audience:
                        type: string
                      icp_description:
                        type: string
                      differentiators:
                        type: array
                        items:
                          type: string
                      alternatives:
                        type: array
                        items:
                          type: string
                      proof_points:
                        type: array
                        items:
                          type: string
                      anti_personas:
                        type: array
                        items:
                          type: string
                      pricing_rationale:
                        type: string
                      voice_guidelines:
                        type: string
                      messaging_pillars:
                        type: array
                        items:
                          type: object
                          properties:
                            pillar:
                              type: string
                            supporting_points:
                              type: array
                              items:
                                type: string
                          required:
                            - pillar
                            - supporting_points
                      objection_responses:
                        type: array
                        items:
                          type: object
                          properties:
                            objection:
                              type: string
                            response:
                              type: string
                          required:
                            - objection
                            - response
                  updated_at:
                    type: string
                    nullable: true
                required:
                  - positioning
                  - updated_at
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/search:
    get:
      tags:
        - Search
      summary: Search documents and entities
      description: Searches documents by default. Pass `entities` to search other entity types too.
      security:
        - ApiKeyAuth: []
      parameters:
        - schema:
            type: string
            minLength: 1
          required: true
          name: query
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 20
          required: false
          name: limit
          in: query
        - schema:
            type: string
            format: uuid
          required: false
          name: folder_id
          in: query
        - schema:
            type: string
            default: documents
            description: "`all`, `documents`, or a comma-separated list such as `document,decision,feature`"
          required: false
          description: "`all`, `documents`, or a comma-separated list such as `document,decision,feature`"
          name: entities
          in: query
        - schema:
            type: string
            enum:
              - all
              - recorded
            default: all
          required: false
          name: decision_authority
          in: query
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      anyOf:
                        - type: object
                          properties:
                            id:
                              type: string
                            title:
                              type: string
                            path:
                              type: string
                            snippet:
                              type: string
                            score:
                              type: number
                            match_kind:
                              type: string
                              enum:
                                - exact_identifier
                                - exact_phrase
                                - mention
                            lifecycle_state:
                              type: string
                            confirmation_status:
                              type: string
                            possibleDuplicates:
                              type: array
                              items:
                                type: object
                                properties:
                                  id:
                                    type: string
                                  title:
                                    type: string
                                  updatedAt:
                                    type: string
                                  relationship:
                                    type: string
                                    enum:
                                      - duplicate_of
                                      - supersedes
                                  selfIsSuperseded:
                                    type: boolean
                                required:
                                  - id
                                  - title
                                  - updatedAt
                                  - relationship
                                  - selfIsSuperseded
                            uncertain:
                              type: boolean
                              enum:
                                - true
                            entityType:
                              type: string
                              enum:
                                - decision
                            authority:
                              type: string
                              enum:
                                - recorded
                                - derived
                          required:
                            - id
                            - title
                            - path
                            - snippet
                            - score
                            - entityType
                            - authority
                        - type: object
                          properties:
                            id:
                              type: string
                            title:
                              type: string
                            path:
                              type: string
                            snippet:
                              type: string
                            score:
                              type: number
                            match_kind:
                              type: string
                              enum:
                                - exact_identifier
                                - exact_phrase
                                - mention
                            lifecycle_state:
                              type: string
                            confirmation_status:
                              type: string
                            possibleDuplicates:
                              type: array
                              items:
                                type: object
                                properties:
                                  id:
                                    type: string
                                  title:
                                    type: string
                                  updatedAt:
                                    type: string
                                  relationship:
                                    type: string
                                    enum:
                                      - duplicate_of
                                      - supersedes
                                  selfIsSuperseded:
                                    type: boolean
                                required:
                                  - id
                                  - title
                                  - updatedAt
                                  - relationship
                                  - selfIsSuperseded
                            uncertain:
                              type: boolean
                              enum:
                                - true
                            entityType:
                              type: string
                              enum:
                                - document
                                - feature
                                - persona
                                - research_signal
                                - competitor
                          required:
                            - id
                            - title
                            - path
                            - snippet
                            - score
                            - entityType
                        - type: object
                          properties:
                            id:
                              type: string
                            title:
                              type: string
                            entityType:
                              type: string
                              enum:
                                - work_item
                          required:
                            - id
                            - title
                            - entityType
                  query:
                    type: string
                  has_more:
                    type: boolean
                  total_count:
                    type: number
                  search_scope_limited:
                    type: boolean
                    enum:
                      - true
                  query_constraints:
                    type: array
                    items:
                      type: object
                      properties:
                        kind:
                          type: string
                          enum:
                            - decision_id
                            - ticket_id
                            - quoted_phrase
                        outcome:
                          type: string
                          enum:
                            - matched
                            - missing_or_unauthorized
                            - unsupported
                            - malformed
                            - unavailable
                            - over_limit
                      required:
                        - kind
                        - outcome
                required:
                  - results
                  - query
                  - has_more
                  - total_count
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Rate limited
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    properties:
                      error:
                        type: string
                      retryAfter:
                        type: integer
                        description: Seconds until the limit resets
                    required:
                      - error
                      - retryAfter
                  - $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/codebase-pack/upload:
    post:
      tags:
        - Codebase
      summary: Upload a packed codebase
      description: Stores a repomix pack made on the caller's machine, in the same place as the nightly server-side pack.
        `tokens` must be the content length divided by four, rounded up, and `hash` the SHA-256 of the content. Needs an
        admin.
      security:
        - ApiKeyAuth: []
      requestBody:
        description: Packed codebase
        content:
          application/json:
            schema:
              type: object
              properties:
                repoIdentifier:
                  type: string
                  minLength: 1
                  maxLength: 300
                  description: "`owner/repo`, or `local/name` for a repo with no remote"
                content:
                  type: string
                  minLength: 1
                  maxLength: 360000
                tokens:
                  type: integer
                  minimum: 0
                  exclusiveMinimum: true
                  maximum: 90000
                mode:
                  type: string
                  enum:
                    - compressed
                    - manifest-only
                    - truncated
                hash:
                  type: string
                  pattern: ^[A-Fa-f0-9]{64}$
                isPrimary:
                  type: boolean
              required:
                - repoIdentifier
                - content
                - tokens
                - mode
                - hash
      responses:
        "200":
          description: Pack stored
          content:
            application/json:
              schema:
                type: object
                properties:
                  action:
                    type: string
                    enum:
                      - created
                      - updated
                      - skipped-nop
                  docId:
                    type: string
                required:
                  - action
                  - docId
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: The organization has no selected GitHub repos
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: Request body too large
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/client-errors/persisted-message-decode:
    post:
      tags:
        - Client errors
      summary: Report a persisted chat message that failed to decode
      description: "BRI-7427: a client reports that a persisted message failed `decodePersistedMessages`. `messageId` is an
        untrusted diagnostic label; the server logs it and never looks up or acts on the row. Rate-limited per user."
      security:
        - ApiKeyAuth: []
        - ClerkSession: []
      requestBody:
        description: Decode failure report
        content:
          application/json:
            schema:
              type: object
              properties:
                messageId:
                  type: string
                  format: uuid
                errorName:
                  type: string
                  enum:
                    - Error
                    - TypeError
                    - SyntaxError
                    - RangeError
                    - UnknownError
              required:
                - messageId
                - errorName
              additionalProperties: false
      responses:
        "200":
          description: Report accepted (or silently dropped once rate-limited)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  reported:
                    type: boolean
                required:
                  - success
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponseWithDetails"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: API key rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitedResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
