asyncapi: 3.0.0
info:
  title: interhuman-api
  version: 1.14.0
  description: ''
servers:
  production:
    host: api.interhuman.ai
    protocol: ws
channels:
  stream_analyze_v1:
    address: /v1/stream/analyze
    title: stream_analyze_v1
    description: Analyze a video stream.
    messages:
      conversation_quality_updated_v1_message:
        $ref: '#/components/messages/conversation_quality_updated_v1_message'
      coverage_dropped_v1_message:
        $ref: '#/components/messages/coverage_dropped_v1_message'
      engagement_updated_v1_message:
        $ref: '#/components/messages/engagement_updated_v1_message'
      session_close_v1_message:
        $ref: '#/components/messages/session_close_v1_message'
      session_closing_v1_message:
        $ref: '#/components/messages/session_closing_v1_message'
      session_ended_v1_message:
        $ref: '#/components/messages/session_ended_v1_message'
      session_ready_v1_message:
        $ref: '#/components/messages/session_ready_v1_message'
      session_updated_v1_message:
        $ref: '#/components/messages/session_updated_v1_message'
      signal_detected_v1_message:
        $ref: '#/components/messages/signal_detected_v1_message'
      signal_ended_v1_message:
        $ref: '#/components/messages/signal_ended_v1_message'
      signal_updated_v1_message:
        $ref: '#/components/messages/signal_updated_v1_message'
      stream_error_v1_message:
        $ref: '#/components/messages/stream_error_v1_message'
      stream_session_config_v1_message:
        $ref: '#/components/messages/stream_session_config_v1_message'
      stream_video_message:
        $ref: '#/components/messages/stream_video_message'
    bindings:
      ws:
        bindingVersion: 0.1.0
        headers:
          type: object
          properties:
            X-Client-Request-Id:
              type: string
              description: >-
                Optional identifier supplied by the client to correlate this
                request with their own logs. When provided, the value is
                recorded alongside the server-assigned correlation ID in
                Interhuman logs to aid lookup and support investigations. This
                header is not echoed back in the response; the server returns
                its own correlation ID in the `X-Correlation-ID` HTTP response
                header.
            Sec-WebSocket-Protocol:
              type: string
              description: >-
                Authentication credential supplied during the WebSocket
                handshake. Pass your API key here when your client cannot set an
                `Authorization` header for WebSocket connections.
              examples:
                - <api_key>
  realtime_analyze_v1:
    address: /v0/realtime/analyze
    title: realtime_analyze_v1
    description: Analyze a real-time video stream.
    messages:
      coverage_dropped_v1_message:
        $ref: '#/components/messages/coverage_dropped_v1_message'
      realtime_feedback_generated_v1_message:
        $ref: '#/components/messages/realtime_feedback_generated_v1_message'
      realtime_session_config_v1_message:
        $ref: '#/components/messages/realtime_session_config_v1_message'
      realtime_session_ready_v1_message:
        $ref: '#/components/messages/realtime_session_ready_v1_message'
      realtime_session_updated_v1_message:
        $ref: '#/components/messages/realtime_session_updated_v1_message'
      session_close_v1_message:
        $ref: '#/components/messages/session_close_v1_message'
      session_closing_v1_message:
        $ref: '#/components/messages/session_closing_v1_message'
      session_ended_v1_message:
        $ref: '#/components/messages/session_ended_v1_message'
      signal_detected_v1_message:
        $ref: '#/components/messages/signal_detected_v1_message'
      signal_ended_v1_message:
        $ref: '#/components/messages/signal_ended_v1_message'
      signal_updated_v1_message:
        $ref: '#/components/messages/signal_updated_v1_message'
      stream_error_v1_message:
        $ref: '#/components/messages/stream_error_v1_message'
      stream_video_message:
        $ref: '#/components/messages/stream_video_message'
      transcript_generated_v1_message:
        $ref: '#/components/messages/transcript_generated_v1_message'
      transcript_updated_v1_message:
        $ref: '#/components/messages/transcript_updated_v1_message'
    bindings:
      ws:
        bindingVersion: 0.1.0
        headers:
          type: object
          properties:
            X-Client-Request-Id:
              type: string
              description: >-
                Optional identifier supplied by the client to correlate this
                request with their own logs. When provided, the value is
                recorded alongside the server-assigned correlation ID in
                Interhuman logs to aid lookup and support investigations. This
                header is not echoed back in the response; the server returns
                its own correlation ID in the `X-Correlation-ID` HTTP response
                header.
            Sec-WebSocket-Protocol:
              type: string
              description: >-
                Authentication credential supplied during the WebSocket
                handshake. Pass your API key here when your client cannot set an
                `Authorization` header for WebSocket connections.
              examples:
                - <api_key>
operations:
  receive_handler:
    action: receive
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: ''
    summary: ''
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/stream_video_message'
  session_close_handler:
    action: receive
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: ''
    summary: ''
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/session_close_v1_message'
  session_config_handler:
    action: receive
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: ''
    summary: ''
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/stream_session_config_v1_message'
  output_conversation_quality_updated:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Carries Conversation Quality Index values for the most recently closed
      cadence period. Emitted at most once per period and only when the caller
      has set at least one CQI ``include`` flag on the session-config message.
      ``data.overall`` is cumulative across the whole session up to the end of
      the just-closed period and is included whenever ``include:
      ["conversation_quality_overall"]`` was supplied. ``data.timeline`` carries
      a single entry covering the just-closed period and is included whenever
      ``include: ["conversation_quality_timeline"]`` was supplied — periods with
      no analyzer-reported signals still emit the timeline; its scores reflect
      any engagement contribution and fall back to all-50 defaults when nothing
      contributes, so the requested section is always present.
    summary: Conversation Quality Updated
    messages:
      - $ref: >-
          #/channels/stream_analyze_v1/messages/conversation_quality_updated_v1_message
  output_coverage_dropped:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Reports that analysis coverage was reduced under backpressure. Emitted
      when the analysis pipeline saturates and has to skip buffered video that
      no surviving analysis window covers. This is an informational notice, not
      an error: the session stays open, subsequent windows continue
      uninterrupted, and the dropped portions of the video are not billed.
      ``data.ranges`` lists the skipped time ranges in absolute
      session-cumulative seconds.
    summary: Coverage Dropped
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/coverage_dropped_v1_message'
  output_engagement_updated:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Reports a change in engagement state. Emitted once when engagement is
      first established for the session, and again only when the detected
      engagement level differs from the most recently emitted level.
      ``data.start`` uses absolute session-cumulative time.
    summary: Engagement Updated
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/engagement_updated_v1_message'
  output_error:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Reports an error encountered while processing the stream. ``data.code``
      carries the machine-readable error id (sub-type), and ``data.segment``
      identifies the incoming caller segment when the failure maps to a specific
      chunk (size validation, quota); analysis-time failures that do not map to
      one chunk carry ``data.segment: null``.
    summary: Error
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/stream_error_v1_message'
  output_session_closing:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Acknowledges that an inbound ``session.close`` text frame was accepted.
      From this point the server rejects new binary video frames, finishes
      analyzing the video it already accepted (emitting the normal result
      envelopes in order), emits final lifecycle envelopes for still-open
      analysis state, sends ``session.ended``, and closes the WebSocket.
      ``data.max_drain_seconds`` is the maximum time the caller should wait for
      ``session.ended`` after this acknowledgment; the session closes earlier
      when the accepted work finishes sooner.
    summary: Session Closing
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/session_closing_v1_message'
  output_session_ended:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      The final message of a gracefully closed session. Emitted after every
      already-accepted analysis window has drained (or the ``max_drain_seconds``
      deadline advertised on ``session.closing`` expired) and after the final
      lifecycle envelopes for still-open analysis state. No further analysis
      messages follow; the server closes the WebSocket (close code 1000)
      immediately after sending it.
    summary: Session Ended
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/session_ended_v1_message'
  output_session_ready:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Acknowledges that the v1 stream session is established. Emitted exactly
      once per session, immediately after the server accepts the WebSocket
      handshake. Carries the session-level contract (idle / max-duration
      timeouts, segment size and duration constraints, supported session-config
      options) so the caller can adapt its producer side without round-tripping
      rejections. Sessions that fail to fully establish close without this
      envelope; a client that has not seen ``session.ready`` must assume the
      session is not ready to receive video.
    summary: Session Ready
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/session_ready_v1_message'
  output_session_updated:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Acknowledges that an inbound ``stream_session_config_v1`` text frame was
      accepted. Carries the consolidated post-apply config (``include``).
    summary: Session Updated
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/session_updated_v1_message'
  output_signal_detected:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Reports that a social signal has transitioned from inactive to active.
      Emitted once when the signal type is first detected for the session, and
      again only when the signal becomes active after a prior ``signal.ended``.
      ``data.start`` uses absolute session-cumulative time.
    summary: Signal Detected
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/signal_detected_v1_message'
  output_signal_ended:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Reports that a previously active social signal is no longer active.
      Emitted when a signal type that was active in the previous analyzed window
      is not present in the current window. ``data.end`` uses absolute
      session-cumulative time.
    summary: Signal Ended
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/signal_ended_v1_message'
  output_signal_updated:
    action: send
    channel:
      $ref: '#/channels/stream_analyze_v1'
    description: >-
      Reports that an already-active social signal experienced a change in
      probability. Emitted when an active signal type's ``probability`` has
      changed from the previous value reported for that signal type (either
      ``signal.detected`` or a prior ``signal.updated``).  ``data.start`` uses
      absolute session-cumulative time.
    summary: Signal Updated
    messages:
      - $ref: '#/channels/stream_analyze_v1/messages/signal_updated_v1_message'
  v1_realtime_receive_handler:
    action: receive
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: ''
    summary: ''
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/stream_video_message'
  v1_realtime_session_close_handler:
    action: receive
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: ''
    summary: ''
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/session_close_v1_message'
  v1_realtime_session_config_handler:
    action: receive
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: ''
    summary: ''
    messages:
      - $ref: >-
          #/channels/realtime_analyze_v1/messages/realtime_session_config_v1_message
  transcript_handler:
    action: receive
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: ''
    summary: ''
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/transcript_updated_v1_message'
  v1_realtime_output_coverage_dropped:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Reports that analysis coverage was reduced under backpressure. Emitted
      when the analysis pipeline saturates and has to skip buffered video that
      no surviving analysis window covers. This is an informational notice, not
      an error: the session stays open, subsequent windows continue
      uninterrupted, and the dropped portions of the video are not billed.
      ``data.ranges`` lists the skipped time ranges in absolute
      session-cumulative seconds.
    summary: Coverage Dropped
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/coverage_dropped_v1_message'
  v1_realtime_output_error:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Reports an error encountered while processing the stream. ``data.code``
      carries the machine-readable error id (sub-type), and ``data.segment``
      identifies the incoming caller segment when the failure maps to a specific
      chunk (size validation, quota); analysis-time failures that do not map to
      one chunk carry ``data.segment: null``.
    summary: Error
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/stream_error_v1_message'
  output_realtime_feedback_generated:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Reports a periodic feedback of the conversation so far. Feedback is
      emitted only when all three conditions hold: the caller supplies
      ``realtime_feedback_instructions`` in ``session.config`` (there is no
      default prompt), at least one signal has been detected, and at least one
      transcript has been received since the previous feedback. Once enabled it
      is paced by the session-config ``realtime_feedback_frequency``
      (``high``/``medium``/``low`` mapped to 10/20/30 seconds of analyzed
      video). Renders the caller-supplied transcript, the accumulated social
      signals about the analyzed speaker, and the caller-supplied configuration
      into a structured prompt, calls the feedback model, and returns the
      guidance text (or ``NO_GUIDANCE``) plus the analyzed interval it covers.
    summary: Feedback Generated
    messages:
      - $ref: >-
          #/channels/realtime_analyze_v1/messages/realtime_feedback_generated_v1_message
  v1_realtime_output_session_closing:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Acknowledges that an inbound ``session.close`` text frame was accepted.
      From this point the server rejects new binary video frames, finishes
      analyzing the video it already accepted (emitting the normal result
      envelopes in order), emits final lifecycle envelopes for still-open
      analysis state, sends ``session.ended``, and closes the WebSocket.
      ``data.max_drain_seconds`` is the maximum time the caller should wait for
      ``session.ended`` after this acknowledgment; the session closes earlier
      when the accepted work finishes sooner.
    summary: Session Closing
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/session_closing_v1_message'
  v1_realtime_output_session_ended:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      The final message of a gracefully closed session. Emitted after every
      already-accepted analysis window has drained (or the ``max_drain_seconds``
      deadline advertised on ``session.closing`` expired) and after the final
      lifecycle envelopes for still-open analysis state. No further analysis
      messages follow; the server closes the WebSocket (close code 1000)
      immediately after sending it.
    summary: Session Ended
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/session_ended_v1_message'
  v1_realtime_output_session_ready:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Acknowledges that the v1 real-time session is established. Emitted exactly
      once per session, immediately after the server accepts the WebSocket
      handshake. Carries the session-level contract (idle / max-duration
      timeouts, segment size constraints, supported session-config options) so
      the caller can adapt its producer side without round-tripping rejections.
      Unlike the stream ``session.ready``, ``supported_session_config_options``
      advertises the real-time options (``realtime_feedback_instructions`` /
      ``realtime_feedback_frequency`` / ``analysis_groups``) and never the
      stream ``include`` / ``goal_dimensions`` options. ``analysis_groups``
      lists only the analysis groups the current ``REALTIME_TRACKS`` setting
      allows.
    summary: Session Ready
    messages:
      - $ref: >-
          #/channels/realtime_analyze_v1/messages/realtime_session_ready_v1_message
  v1_realtime_output_session_updated:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Acknowledges that an inbound ``realtime_session_config_v1`` text frame was
      accepted. Carries the consolidated post-apply real-time config
      (``realtime_feedback_instructions`` / ``realtime_feedback_frequency`` /
      ``analysis_groups``). ``analysis_groups`` is the effective selection in
      force, clamped to what ``REALTIME_TRACKS`` allows.
    summary: Session Updated
    messages:
      - $ref: >-
          #/channels/realtime_analyze_v1/messages/realtime_session_updated_v1_message
  v1_realtime_output_signal_detected:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Reports that a social signal has transitioned from inactive to active.
      Emitted once when the signal type is first detected for the session, and
      again only when the signal becomes active after a prior ``signal.ended``.
      ``data.start`` uses absolute session-cumulative time.
    summary: Signal Detected
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/signal_detected_v1_message'
  v1_realtime_output_signal_ended:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Reports that a previously active social signal is no longer active.
      Emitted when a signal type that was active in the previous analyzed window
      is not present in the current window. ``data.end`` uses absolute
      session-cumulative time.
    summary: Signal Ended
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/signal_ended_v1_message'
  v1_realtime_output_signal_updated:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Reports that an already-active social signal experienced a change in
      probability. Emitted when an active signal type's ``probability`` has
      changed from the previous value reported for that signal type (either
      ``signal.detected`` or a prior ``signal.updated``).  ``data.start`` uses
      absolute session-cumulative time.
    summary: Signal Updated
    messages:
      - $ref: '#/channels/realtime_analyze_v1/messages/signal_updated_v1_message'
  output_transcript_generated:
    action: send
    channel:
      $ref: '#/channels/realtime_analyze_v1'
    description: >-
      Streams the server's own ASR transcript of the analyzed audio, one
      envelope per analyzed window whenever the ``asr`` track produced new
      speech. Because analysis windows overlap, the server de-overlaps using
      word timestamps and emits only the text not already sent, so concatenating
      the ``text`` of successive ``transcript.generated`` events reconstructs
      the running transcript without duplication. This is distinct from the
      inbound ``transcript.updated`` frame, which carries a caller-supplied
      transcript.
    summary: Transcript Generated
    messages:
      - $ref: >-
          #/channels/realtime_analyze_v1/messages/transcript_generated_v1_message
components:
  messages:
    conversation_quality_updated_v1_message:
      payload:
        $ref: '#/components/schemas/ConversationQualityUpdatedV1Message'
      title: Conversation Quality Updated
      description: >-
        Carries Conversation Quality Index values for the most recently closed
        cadence period. Emitted at most once per period and only when the caller
        has set at least one CQI ``include`` flag on the session-config message.
        ``data.overall`` is cumulative across the whole session up to the end of
        the just-closed period and is included whenever ``include:
        ["conversation_quality_overall"]`` was supplied. ``data.timeline``
        carries a single entry covering the just-closed period and is included
        whenever ``include: ["conversation_quality_timeline"]`` was supplied —
        periods with no analyzer-reported signals still emit the timeline; its
        scores reflect any engagement contribution and fall back to all-50
        defaults when nothing contributes, so the requested section is always
        present.
      examples:
        - name: Conversation Quality Updated
          payload:
            type: conversation_quality.updated
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              overall:
                quality_index: 72
                clarity: 67
                authority: 68
                energy: 80
                rapport: 75
                learning: 70
              timeline:
                - start: 0
                  end: 11
                  values:
                    quality_index: 70
                    clarity: 69
                    authority: 70
                    energy: 78
                    rapport: 77
                    learning: 68
    coverage_dropped_v1_message:
      payload:
        $ref: '#/components/schemas/CoverageDroppedV1Message'
      title: Coverage Dropped
      description: >-
        Reports that analysis coverage was reduced under backpressure. Emitted
        when the analysis pipeline saturates and has to skip buffered video that
        no surviving analysis window covers. This is an informational notice,
        not an error: the session stays open, subsequent windows continue
        uninterrupted, and the dropped portions of the video are not billed.
        ``data.ranges`` lists the skipped time ranges in absolute
        session-cumulative seconds.
      examples:
        - name: Coverage Dropped
          payload:
            type: coverage.dropped
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              ranges:
                - start: 8
                  end: 10
    engagement_updated_v1_message:
      payload:
        $ref: '#/components/schemas/EngagementUpdatedV1Message'
      title: Engagement Updated
      description: >-
        Reports a change in engagement state. Emitted once when engagement is
        first established for the session, and again only when the detected
        engagement level differs from the most recently emitted level.
        ``data.start`` uses absolute session-cumulative time.
      examples:
        - name: Engagement Updated
          payload:
            type: engagement.updated
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              state: engaged
              start: 42
    realtime_feedback_generated_v1_message:
      payload:
        $ref: '#/components/schemas/RealtimeFeedbackGeneratedV1Message'
      title: Feedback Generated
      description: >-
        Reports a periodic feedback of the conversation so far. Feedback is
        emitted only when all three conditions hold: the caller supplies
        ``realtime_feedback_instructions`` in ``session.config`` (there is no
        default prompt), at least one signal has been detected, and at least one
        transcript has been received since the previous feedback. Once enabled
        it is paced by the session-config ``realtime_feedback_frequency``
        (``high``/``medium``/``low`` mapped to 10/20/30 seconds of analyzed
        video). Renders the caller-supplied transcript, the accumulated social
        signals about the analyzed speaker, and the caller-supplied
        configuration into a structured prompt, calls the feedback model, and
        returns the guidance text (or ``NO_GUIDANCE``) plus the analyzed
        interval it covers.
      examples:
        - name: Feedback Generated
          payload:
            type: realtime_feedback.generated
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              text: >-
                Speaker 1 agreed but sounds unsure — invite them to name what
                still feels unresolved.
              start: 0
              end: 20
    realtime_session_config_v1_message:
      title: Real-time Session Config
      summary: Caller-supplied session configuration for the real-time endpoint.
      description: >-
        Caller-supplied session configuration for the real-time endpoint.


        Unlike the stream session config, the real-time config does **not**
        accept

        the conversation-quality ``include`` flags: the real-time endpoint does
        not

        emit ``conversation_quality.updated`` or ``engagement.updated``, so
        those

        flags have no effect and are rejected. It carries the shared

        ``goal_dimensions`` field and adds the feedback controls. Like the
        stream

        config, this message can be sent at any time during the session; the
        most

        recent message wins.


        Feedback is opt-in: ``realtime_feedback_instructions`` is the switch
        that enables it.

        There is no default prompt, so feedback runs only when the caller
        supplies

        a non-empty ``realtime_feedback_instructions``;
        ``realtime_feedback_frequency`` then paces it.

        The backend always governs the feedback system prompt and output
        contract;

        ``realtime_feedback_instructions`` supplies the session-scoped
        configuration block

        (goal/domain/context/focus/tone) that the feedback step treats as
        untrusted

        configuration data. It is never configured through environment
        variables.


        ``analysis_groups`` lets the caller choose which top-level analysis
        surfaces

        (``video`` / ``visual`` / ``audio``) are active for their own session,
        always

        a subset of what the operator has enabled via ``REALTIME_TRACKS``.
      payload:
        $ref: '#/components/schemas/RealtimeSessionConfigV1'
      examples:
        - name: Example 1
          payload:
            analysis_groups:
              - audio
              - visual
            realtime_feedback_frequency: medium
            realtime_feedback_instructions: >-
              Goal: help me close a sales call. Keep the guidance warm and
              concise.
    realtime_session_ready_v1_message:
      payload:
        $ref: '#/components/schemas/RealtimeSessionReadyV1Message'
      title: Session Ready
      description: >-
        Acknowledges that the v1 real-time session is established. Emitted
        exactly once per session, immediately after the server accepts the
        WebSocket handshake. Carries the session-level contract (idle /
        max-duration timeouts, segment size constraints, supported
        session-config options) so the caller can adapt its producer side
        without round-tripping rejections. Unlike the stream ``session.ready``,
        ``supported_session_config_options`` advertises the real-time options
        (``realtime_feedback_instructions`` / ``realtime_feedback_frequency`` /
        ``analysis_groups``) and never the stream ``include`` /
        ``goal_dimensions`` options. ``analysis_groups`` lists only the analysis
        groups the current ``REALTIME_TRACKS`` setting allows.
      examples:
        - name: Session Ready
          payload:
            type: session.ready
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              session_idle_timeout_seconds: 300
              session_max_duration_seconds: 3600
              min_segment_size_bytes: 1
              max_segment_size_bytes: 33554432
              supported_session_config_options:
                realtime_feedback_instructions: string
                realtime_feedback_frequency:
                  - high
                  - medium
                  - low
                analysis_groups:
                  - video
                  - visual
                  - audio
    realtime_session_updated_v1_message:
      payload:
        $ref: '#/components/schemas/RealtimeSessionUpdatedV1Message'
      title: Session Updated
      description: >-
        Acknowledges that an inbound ``realtime_session_config_v1`` text frame
        was accepted. Carries the consolidated post-apply real-time config
        (``realtime_feedback_instructions`` / ``realtime_feedback_frequency`` /
        ``analysis_groups``). ``analysis_groups`` is the effective selection in
        force, clamped to what ``REALTIME_TRACKS`` allows.
      examples:
        - name: Session Updated
          payload:
            type: session.updated
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              realtime_feedback_instructions: >-
                Goal: help me close a sales call. Keep the guidance warm and
                concise.
              realtime_feedback_frequency: medium
              analysis_groups:
                - audio
                - visual
    session_close_v1_message:
      title: Session Close
      summary: Inbound ``session.close`` text frame.
      description: >-
        Inbound ``session.close`` text frame.


        Tells the server the caller is done sending video and wants a graceful

        end-of-analysis handshake: the server acknowledges with

        ``session.closing`` (carrying ``max_drain_seconds``), rejects any
        further

        binary video frames, finishes analyzing the already-accepted video and

        emits its normal result envelopes in order, emits final lifecycle

        envelopes for still-open analysis state, sends ``session.ended``, and

        closes the WebSocket. Unknown fields are rejected (with a non-fatal

        ``error`` envelope; the session stays open) so a caller typo cannot be

        silently misread as a close request.


        Only binary video is refused after acceptance. Text messages remain

        accepted while the session drains: a session-config update is applied

        and acknowledged as usual and governs the analysis still draining, a

        duplicate ``session.close`` is ignored, and (on the real-time endpoint)

        a ``transcript.updated`` still lands and is rendered into any real-time
        feedback

        that runs during the drain. Malformed text frames received during the

        drain are rejected with a non-fatal ``error`` envelope rather than

        closing the connection early, so the caller always gets its

        ``session.ended``.
      payload:
        $ref: '#/components/schemas/SessionCloseV1'
      examples:
        - name: Example 1
          payload:
            type: session.close
    session_closing_v1_message:
      payload:
        $ref: '#/components/schemas/SessionClosingV1Message'
      title: Session Closing
      description: >-
        Acknowledges that an inbound ``session.close`` text frame was accepted.
        From this point the server rejects new binary video frames, finishes
        analyzing the video it already accepted (emitting the normal result
        envelopes in order), emits final lifecycle envelopes for still-open
        analysis state, sends ``session.ended``, and closes the WebSocket.
        ``data.max_drain_seconds`` is the maximum time the caller should wait
        for ``session.ended`` after this acknowledgment; the session closes
        earlier when the accepted work finishes sooner.
      examples:
        - name: Session Closing
          payload:
            type: session.closing
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              max_drain_seconds: 60
    session_ended_v1_message:
      payload:
        $ref: '#/components/schemas/SessionEndedV1Message'
      title: Session Ended
      description: >-
        The final message of a gracefully closed session. Emitted after every
        already-accepted analysis window has drained (or the
        ``max_drain_seconds`` deadline advertised on ``session.closing``
        expired) and after the final lifecycle envelopes for still-open analysis
        state. No further analysis messages follow; the server closes the
        WebSocket (close code 1000) immediately after sending it.
      examples:
        - name: Session Ended
          payload:
            type: session.ended
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              reason: client_shutdown
    session_ready_v1_message:
      payload:
        $ref: '#/components/schemas/SessionReadyV1Message'
      title: Session Ready
      description: >-
        Acknowledges that the v1 stream session is established. Emitted exactly
        once per session, immediately after the server accepts the WebSocket
        handshake. Carries the session-level contract (idle / max-duration
        timeouts, segment size and duration constraints, supported
        session-config options) so the caller can adapt its producer side
        without round-tripping rejections. Sessions that fail to fully establish
        close without this envelope; a client that has not seen
        ``session.ready`` must assume the session is not ready to receive video.
      examples:
        - name: Session Ready
          payload:
            type: session.ready
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              session_idle_timeout_seconds: 300
              session_max_duration_seconds: 3600
              min_segment_size_bytes: 1
              max_segment_size_bytes: 33554432
              supported_session_config_options:
                include:
                  - conversation_quality_overall
                  - conversation_quality_timeline
    session_updated_v1_message:
      payload:
        $ref: '#/components/schemas/SessionUpdatedV1Message'
      title: Session Updated
      description: >-
        Acknowledges that an inbound ``stream_session_config_v1`` text frame was
        accepted. Carries the consolidated post-apply config (``include``).
      examples:
        - name: Session Updated
          payload:
            type: session.updated
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              include:
                - conversation_quality_overall
    signal_detected_v1_message:
      payload:
        $ref: '#/components/schemas/SignalDetectedV1Message'
      title: Signal Detected
      description: >-
        Reports that a social signal has transitioned from inactive to active.
        Emitted once when the signal type is first detected for the session, and
        again only when the signal becomes active after a prior
        ``signal.ended``. ``data.start`` uses absolute session-cumulative time.
      examples:
        - name: Signal Detected
          payload:
            type: signal.detected
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              signal_type: agreement
              start: 3
              probability: high
              rationale: Subject nodded repeatedly while maintaining eye contact.
    signal_ended_v1_message:
      payload:
        $ref: '#/components/schemas/SignalEndedV1Message'
      title: Signal Ended
      description: >-
        Reports that a previously active social signal is no longer active.
        Emitted when a signal type that was active in the previous analyzed
        window is not present in the current window. ``data.end`` uses absolute
        session-cumulative time.
      examples:
        - name: Signal Ended
          payload:
            type: signal.ended
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              signal_type: agreement
              end: 14
    signal_updated_v1_message:
      payload:
        $ref: '#/components/schemas/SignalUpdatedV1Message'
      title: Signal Updated
      description: >-
        Reports that an already-active social signal experienced a change in
        probability. Emitted when an active signal type's ``probability`` has
        changed from the previous value reported for that signal type (either
        ``signal.detected`` or a prior ``signal.updated``).  ``data.start`` uses
        absolute session-cumulative time.
      examples:
        - name: Signal Updated
          payload:
            type: signal.updated
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              signal_type: agreement
              start: 6
              probability: medium
              rationale: Subject nodded once but then looked away.
    stream_error_v1_message:
      payload:
        $ref: '#/components/schemas/StreamErrorV1Message'
      title: Error
      description: >-
        Reports an error encountered while processing the stream. ``data.code``
        carries the machine-readable error id (sub-type), and ``data.segment``
        identifies the incoming caller segment when the failure maps to a
        specific chunk (size validation, quota); analysis-time failures that do
        not map to one chunk carry ``data.segment: null``.
      examples:
        - name: Error
          payload:
            type: error
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              code: ih6002
              message: >-
                WebSocket message too large. Individual video chunks must not
                exceed 32 MB.
              link: >-
                https://docs.interhuman.ai/api-reference/error-handling#ih6002-message-too-large
              segment: 2
    stream_session_config_v1_message:
      title: Session Config
      summary: >-
        Optional caller-supplied session configuration. This message can be sent
        at any time to update the configuration.
      description: >-
        Optional caller-supplied session configuration. This message can be sent
        at any time to update the configuration.
      payload:
        $ref: '#/components/schemas/StreamSessionConfigV1'
      examples:
        - name: Example 1
          payload:
            include:
              - conversation_quality_overall
    stream_video_message:
      title: Video (bytes)
      summary: >-
        Binary video segment sent by the client for analysis. Each segment must
        not exceed 32MB. Accepts the following formats: mp4, avi, mov, mkv,
        mpeg-ts, mpeg-2-ts, webm.
      payload:
        format: binary
      examples:
        - name: Video Message
          payload: []
    transcript_generated_v1_message:
      payload:
        $ref: '#/components/schemas/TranscriptGeneratedV1Message'
      title: Transcript Generated
      description: >-
        Streams the server's own ASR transcript of the analyzed audio, one
        envelope per analyzed window whenever the ``asr`` track produced new
        speech. Because analysis windows overlap, the server de-overlaps using
        word timestamps and emits only the text not already sent, so
        concatenating the ``text`` of successive ``transcript.generated`` events
        reconstructs the running transcript without duplication. This is
        distinct from the inbound ``transcript.updated`` frame, which carries a
        caller-supplied transcript.
      examples:
        - name: Transcript Generated
          payload:
            type: transcript.generated
            timestamp: '2025-01-01T00:00:00.000000Z'
            correlation_id: 550e8400-e29b-41d4-a716-446655440000
            data:
              text: and then we can move on to the next item
              start: 6
              end: 8
    transcript_updated_v1_message:
      title: Transcript Update
      summary: Inbound ``transcript.updated`` text frame.
      description: >-
        Inbound ``transcript.updated`` text frame.


        Lets the caller provide (and update) a transcript during the session.
        The

        ``transcript`` payload is a list of :class:`RealtimeTranscriptSegment`

        (``{start, end, text, speaker}``) entries; the most recent value is
        stored

        for the session and rendered into the feedback prompt.
      payload:
        $ref: '#/components/schemas/TranscriptUpdatedV1'
      examples:
        - name: Example 1
          payload:
            transcript:
              - end: 2.28
                speaker: 0
                start: 0.44
                text: Yeah, yeah, exactly.
              - end: 5.88
                speaker: 0
                start: 3
                text: Um I think that that makes sense.
            type: transcript.updated
  schemas:
    AnalysisGroup:
      description: >-
        Caller-facing real-time analysis groups.


        Each group is a top-level analysis surface the caller can switch on or
        off

        for their own ``WS /v0/realtime/analyze`` session, gated by the
        operator's

        ``REALTIME_TRACKS`` allow-list. A group maps to one or more concrete

        analysis tracks:


        - ``video``  -> the Inter-1 segment-analysis track (``inter1``)

        - ``visual`` -> the visual-signals track (``visual_signals``)

        - ``audio``  -> the in-process audio track/processor family (prosody,
        ASR,
          vocal attributes, sound events, diarization, transcript emotion)

        The concrete track names behind each group, and the resolution against

        ``REALTIME_TRACKS``, live in :mod:`services.realtime_tracks`.
      enum:
        - video
        - visual
        - audio
      title: AnalysisGroup
      type: string
    ConversationQualityTimelineEntry:
      description: Conversation quality values for a single time window in the timeline.
      properties:
        start:
          description: Window start time in seconds, in absolute session-cumulative time.
          examples:
            - 0
          title: Start Time
          type: number
        end:
          description: Window end time in seconds, in absolute session-cumulative time.
          examples:
            - 10
          title: End Time
          type: number
        values:
          $ref: '#/components/schemas/ConversationQualityValues'
          description: Conversation quality dimension scores for this time window.
          title: Values
      required:
        - start
        - end
        - values
      title: ConversationQualityTimelineEntry
      type: object
    ConversationQualityUpdatedV1Data:
      description: >-
        Payload for the ``conversation_quality.updated`` event.


        ``overall`` is non-null when the session-config message specifies

        ``include: ["conversation_quality_overall"]``, and ``timeline`` is

        non-null when it specifies ``include:
        ["conversation_quality_timeline"]``.

        Either or both may be ``null`` — the event is still emitted as long

        as at least one CQI flag was requested and the cadence rules

        permit it.
      properties:
        overall:
          description: >-
            Aggregated conversation quality scores cumulative across the whole
            session up to the end of the most recently closed cadence period.
            Non-null when ``include: ["conversation_quality_overall"]`` was
            supplied on the session-config message; ``null`` otherwise.
          $ref: '#/components/schemas/ConversationQualityValues'
        timeline:
          anyOf:
            - items:
                $ref: '#/components/schemas/ConversationQualityTimelineEntry'
              type: array
            - type: 'null'
          description: >-
            Per-period conversation quality entries. The stream emits a single
            entry spanning the most recently closed cadence period. Non-null
            when ``include: ["conversation_quality_timeline"]`` was supplied on
            the session-config message *and* the period contained at least one
            analyzer-reported signal; ``null`` otherwise.
          title: Timeline
      title: ConversationQualityUpdatedV1Data
      type: object
    ConversationQualityUpdatedV1Message:
      description: v1 ``conversation_quality.updated`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: conversation_quality.updated
          default: conversation_quality.updated
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``conversation_quality.updated``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/ConversationQualityUpdatedV1Data'
          description: Per-event payload carrying the requested CQI sections.
      required:
        - timestamp
        - data
      title: ConversationQualityUpdatedV1Message
      type: object
    ConversationQualityValues:
      description: >-
        Aggregated conversation quality scores for the entire conversation.


        Added when `conversation_quality_overall` is included in the Include
        flags.
      properties:
        quality_index:
          description: >-
            Overall conversation quality index (0-100). Mean of the five
            dimension scores.
          examples:
            - 72
          title: Quality Index
          type: number
        clarity:
          description: >-
            Clarity / Structure dimension score (0-100). Returns 50 when no
            diagnostic evidence is available for this dimension.
          examples:
            - 67
          title: Clarity
          type: number
        authority:
          description: >-
            Authority / Credibility dimension score (0-100). Returns 50 when no
            diagnostic evidence is available for this dimension.
          examples:
            - 68
          title: Authority
          type: number
        energy:
          description: >-
            Energy / Presence dimension score (0-100). Returns 50 when no
            diagnostic evidence is available for this dimension.
          examples:
            - 80
          title: Energy
          type: number
        rapport:
          description: >-
            Rapport / Relational Safety dimension score (0-100). Returns 50 when
            no diagnostic evidence is available for this dimension.
          examples:
            - 75
          title: Rapport
          type: number
        learning:
          description: >-
            Learning / Exploration dimension score (0-100). Returns 50 when no
            diagnostic evidence is available for this dimension.
          examples:
            - 70
          title: Learning
          type: number
      required:
        - quality_index
        - clarity
        - authority
        - energy
        - rapport
        - learning
      title: ConversationQualityValues
      type: object
    CoverageDroppedRangeV1:
      description: |-
        A single contiguous time range skipped under analysis backpressure.

        Times are in seconds, in absolute session-cumulative time, matching the
        timestamps carried by every other v1 envelope.
      properties:
        start:
          description: >-
            Start of the dropped range, in seconds, in absolute
            session-cumulative time.
          examples:
            - 8
          title: Start
          type: number
        end:
          description: >-
            End of the dropped range, in seconds, in absolute session-cumulative
            time.
          examples:
            - 10
          title: End
          type: number
      required:
        - start
        - end
      title: CoverageDroppedRangeV1
      type: object
    CoverageDroppedV1Data:
      description: |-
        Payload for the ``coverage.dropped`` event.

        Lists the time ranges that the analysis pipeline skipped when it
        saturated and shed buffered video. Dropped portions of the video are
        expected, recoverable degradation — the session stays open and
        continues analyzing subsequent windows — and they are **not billed**.
      properties:
        ranges:
          description: >-
            Disjoint, ascending time ranges that were dropped without analysis.
            These portions of the video are not billed.
          examples:
            - - end: 10
                start: 8
          items:
            $ref: '#/components/schemas/CoverageDroppedRangeV1'
          title: Ranges
          type: array
      required:
        - ranges
      title: CoverageDroppedV1Data
      type: object
    CoverageDroppedV1Message:
      description: v1 ``coverage.dropped`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: coverage.dropped
          default: coverage.dropped
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``coverage.dropped``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/CoverageDroppedV1Data'
          description: Per-event payload listing the dropped time ranges.
      required:
        - timestamp
        - data
      title: CoverageDroppedV1Message
      type: object
    EngagementLevel:
      description: Engagement state levels derived from model signals.
      enum:
        - engaged
        - neutral
        - disengaged
      title: EngagementLevel
      type: string
    EngagementUpdatedV1Data:
      description: Payload for the ``engagement.updated`` event.
      properties:
        state:
          $ref: '#/components/schemas/EngagementLevel'
          description: The newly observed engagement level.
          examples:
            - engaged
        start:
          description: >-
            Time at which ``state`` is first observed, in seconds, in absolute
            session-cumulative time.
          examples:
            - 42
          title: Start
          type: number
      required:
        - state
        - start
      title: EngagementUpdatedV1Data
      type: object
    EngagementUpdatedV1Message:
      description: v1 ``engagement.updated`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: engagement.updated
          default: engagement.updated
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``engagement.updated``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/EngagementUpdatedV1Data'
          description: Per-event payload describing the new engagement state.
      required:
        - timestamp
        - data
      title: EngagementUpdatedV1Message
      type: object
    GoalDimension:
      description: >-
        Conversation quality dimensions a caller can flag as a session goal.


        The values map one-to-one onto the five CQI quality dimensions defined
        in

        ``services.cqi.DIMENSION_KEYS``:


        * ``clarity`` — Clarity / Structure

        * ``authority`` — Authority / Credibility

        * ``energy`` — Energy / Presence

        * ``rapport`` — Rapport / Relational Safety

        * ``learning`` — Learning / Exploration
      enum:
        - clarity
        - authority
        - energy
        - rapport
        - learning
      title: GoalDimension
      type: string
    IncludeFlag:
      description: >-
        Use these flags to control which conversation quality sections are
        included in the response.


        `conversation_quality_overall`: Include overall conversation quality
        index.

        `conversation_quality_timeline`: Include conversation quality timeline.
      enum:
        - conversation_quality_overall
        - conversation_quality_timeline
      title: IncludeFlag
      type: string
    Probability:
      description: Signal probability levels.
      enum:
        - high
        - medium
        - low
      title: Probability
      type: string
    Real-time Session Config:
      additionalProperties: false
      description: >-
        Caller-supplied session configuration for the real-time endpoint.


        Unlike the stream session config, the real-time config does **not**
        accept

        the conversation-quality ``include`` flags: the real-time endpoint does
        not

        emit ``conversation_quality.updated`` or ``engagement.updated``, so
        those

        flags have no effect and are rejected. It carries the shared

        ``goal_dimensions`` field and adds the feedback controls. Like the
        stream

        config, this message can be sent at any time during the session; the
        most

        recent message wins.


        Feedback is opt-in: ``realtime_feedback_instructions`` is the switch
        that enables it.

        There is no default prompt, so feedback runs only when the caller
        supplies

        a non-empty ``realtime_feedback_instructions``;
        ``realtime_feedback_frequency`` then paces it.

        The backend always governs the feedback system prompt and output
        contract;

        ``realtime_feedback_instructions`` supplies the session-scoped
        configuration block

        (goal/domain/context/focus/tone) that the feedback step treats as
        untrusted

        configuration data. It is never configured through environment
        variables.


        ``analysis_groups`` lets the caller choose which top-level analysis
        surfaces

        (``video`` / ``visual`` / ``audio``) are active for their own session,
        always

        a subset of what the operator has enabled via ``REALTIME_TRACKS``.
      examples:
        - analysis_groups:
            - audio
            - visual
          realtime_feedback_frequency: medium
          realtime_feedback_instructions: >-
            Goal: help me close a sales call. Keep the guidance warm and
            concise.
      properties:
        realtime_feedback_instructions:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Configuration block for the periodic feedback step, and the switch
            that enables feedback: feedback runs only when this is set to a
            non-empty value, and there is no default prompt. It sets the goal,
            domain/context, and the kind of guidance you want (focus, tone,
            output style). The backend treats it as untrusted configuration data
            inside the feedback prompt: it shapes the direction of the guidance
            but cannot override the authoritative system prompt or output
            contract. When absent, `null`, or empty, the feedback step is
            disabled and no `realtime_feedback.generated` messages are emitted.
            This field is session-scoped and is never configured through
            environment variables.
          examples:
            - >-
              Goal: help me close a sales call. Keep the guidance warm and
              concise.
          title: Realtime Feedback Instructions
        realtime_feedback_frequency:
          description: >-
            How often to run the feedback step, measured in analyzed-video
            coverage: `high` runs every 10 seconds of analyzed video, `medium`
            every 20 seconds, and `low` every 30 seconds. This only takes effect
            once `realtime_feedback_instructions` has enabled feedback; without
            it, no `realtime_feedback.generated` messages are emitted regardless
            of this value. The frequency gates only when feedback runs — it does
            not change the stride cadence at which analysis tracks execute.
          examples:
            - medium
          $ref: '#/components/schemas/RealtimeFeedbackFrequency'
        analysis_groups:
          anyOf:
            - items:
                $ref: '#/components/schemas/AnalysisGroup'
              minItems: 1
              type: array
            - type: 'null'
          description: >-
            Top-level analysis surfaces to run for this session, any subset of
            `video` (Inter-1 social-signal analysis), `visual` (visual signals),
            and `audio` (the in-process audio tracks). Each selected group is
            gated by the server's `REALTIME_TRACKS` setting: a group the server
            has not enabled is rejected, and a selected group runs only the
            concrete tracks that `REALTIME_TRACKS` actually enables. When
            omitted, the default is `audio` + `visual` (not `video`), clamped to
            the groups the server allows; if none of those defaults are allowed,
            every allowed group is used so the session still analyzes. The
            values the server allows are advertised on `session.ready` under
            `supported_session_config_options.analysis_groups`.
          examples:
            - - audio
              - visual
          title: Analysis Groups
      title: Real-time Session Config
      type: object
    Real-time Supported Session Config Options:
      description: >-
        Supported session-config options advertised on the real-time
        ``session.ready``.


        Mirrors the field names of :class:`RealtimeSessionConfigV1`. Unlike the
        stream

        options, the real-time endpoint advertises only its feedback controls
        and

        the analysis-group selection, and never the stream ``include`` /

        ``goal_dimensions`` options, which are not part of the real-time
        contract.
      properties:
        realtime_feedback_instructions:
          const: string
          default: string
          description: >-
            Accepted type for the ``realtime_feedback_instructions`` field of
            :class:`RealtimeSessionConfigV1`. It takes free-form text rather
            than an enumerable set of values, so its accepted JSON type
            (``string``) is advertised instead of a value list.
          examples:
            - string
          title: Realtime Feedback Instructions
          type: string
        realtime_feedback_frequency:
          description: >-
            Supported values for the ``realtime_feedback_frequency`` field of
            :class:`RealtimeSessionConfigV1`.
          examples:
            - - high
              - medium
              - low
          items:
            $ref: '#/components/schemas/RealtimeFeedbackFrequency'
          title: Realtime Feedback Frequency
          type: array
        analysis_groups:
          description: >-
            Analysis groups the caller may select for the ``analysis_groups``
            field of :class:`RealtimeSessionConfigV1`. Limited to the groups the
            current ``REALTIME_TRACKS`` setting enables, so a caller can
            discover the allowed surface at connect time without round-tripping
            a rejection.
          examples:
            - - video
              - visual
              - audio
          items:
            $ref: '#/components/schemas/AnalysisGroup'
          title: Analysis Groups
          type: array
      required:
        - realtime_feedback_frequency
        - analysis_groups
      title: Real-time Supported Session Config Options
      type: object
    RealtimeFeedbackFrequency:
      description: >-
        How often the real-time feedback step runs, by analyzed-video coverage.


        The frequency gates *when* feedback runs; it does not change the stride

        cadence at which analysis tracks execute. Tracks keep running at the
        normal

        rolling-window cadence and feedback fires once the selected amount of

        analyzed video has accumulated since the previous feedback.
      enum:
        - high
        - medium
        - low
      title: RealtimeFeedbackFrequency
      type: string
    RealtimeFeedbackGeneratedV1Data:
      description: |-
        Payload for the ``realtime_feedback.generated`` event.

        Carries the generated text returned by the feedback LLM plus the start
        time of the analyzed interval the feedback covers, in absolute
        session-cumulative seconds.
      properties:
        text:
          description: >-
            The guidance text returned by the feedback model — one short
            recommendation for the responding speaker, or ``NO_GUIDANCE`` when
            the signals warrant no adjustment.
          examples:
            - >-
              Speaker 1 agreed but sounds unsure — invite them to name what
              still feels unresolved.
          title: Text
          type: string
        start:
          description: >-
            Start of the analyzed interval this feedback covers, in seconds, in
            absolute session-cumulative time.
          examples:
            - 0
          title: Start
          type: number
        end:
          description: >-
            End of the analyzed interval this feedback covers, in seconds, in
            absolute session-cumulative time.
          examples:
            - 20
          title: End
          type: number
      required:
        - text
        - start
        - end
      title: RealtimeFeedbackGeneratedV1Data
      type: object
    RealtimeFeedbackGeneratedV1Message:
      description: v1 ``realtime_feedback.generated`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: realtime_feedback.generated
          default: realtime_feedback.generated
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``realtime_feedback.generated``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/RealtimeFeedbackGeneratedV1Data'
          description: Per-event payload carrying the generated text and interval.
      required:
        - timestamp
        - data
      title: RealtimeFeedbackGeneratedV1Message
      type: object
    RealtimeSessionConfigV1:
      additionalProperties: false
      description: >-
        Caller-supplied session configuration for the real-time endpoint.


        Unlike the stream session config, the real-time config does **not**
        accept

        the conversation-quality ``include`` flags: the real-time endpoint does
        not

        emit ``conversation_quality.updated`` or ``engagement.updated``, so
        those

        flags have no effect and are rejected. It carries the shared

        ``goal_dimensions`` field and adds the feedback controls. Like the
        stream

        config, this message can be sent at any time during the session; the
        most

        recent message wins.


        Feedback is opt-in: ``realtime_feedback_instructions`` is the switch
        that enables it.

        There is no default prompt, so feedback runs only when the caller
        supplies

        a non-empty ``realtime_feedback_instructions``;
        ``realtime_feedback_frequency`` then paces it.

        The backend always governs the feedback system prompt and output
        contract;

        ``realtime_feedback_instructions`` supplies the session-scoped
        configuration block

        (goal/domain/context/focus/tone) that the feedback step treats as
        untrusted

        configuration data. It is never configured through environment
        variables.


        ``analysis_groups`` lets the caller choose which top-level analysis
        surfaces

        (``video`` / ``visual`` / ``audio``) are active for their own session,
        always

        a subset of what the operator has enabled via ``REALTIME_TRACKS``.
      examples:
        - analysis_groups:
            - audio
            - visual
          realtime_feedback_frequency: medium
          realtime_feedback_instructions: >-
            Goal: help me close a sales call. Keep the guidance warm and
            concise.
      properties:
        realtime_feedback_instructions:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Configuration block for the periodic feedback step, and the switch
            that enables feedback: feedback runs only when this is set to a
            non-empty value, and there is no default prompt. It sets the goal,
            domain/context, and the kind of guidance you want (focus, tone,
            output style). The backend treats it as untrusted configuration data
            inside the feedback prompt: it shapes the direction of the guidance
            but cannot override the authoritative system prompt or output
            contract. When absent, `null`, or empty, the feedback step is
            disabled and no `realtime_feedback.generated` messages are emitted.
            This field is session-scoped and is never configured through
            environment variables.
          examples:
            - >-
              Goal: help me close a sales call. Keep the guidance warm and
              concise.
          title: Realtime Feedback Instructions
        realtime_feedback_frequency:
          description: >-
            How often to run the feedback step, measured in analyzed-video
            coverage: `high` runs every 10 seconds of analyzed video, `medium`
            every 20 seconds, and `low` every 30 seconds. This only takes effect
            once `realtime_feedback_instructions` has enabled feedback; without
            it, no `realtime_feedback.generated` messages are emitted regardless
            of this value. The frequency gates only when feedback runs — it does
            not change the stride cadence at which analysis tracks execute.
          examples:
            - medium
          $ref: '#/components/schemas/RealtimeFeedbackFrequency'
        analysis_groups:
          anyOf:
            - items:
                $ref: '#/components/schemas/AnalysisGroup'
              minItems: 1
              type: array
            - type: 'null'
          description: >-
            Top-level analysis surfaces to run for this session, any subset of
            `video` (Inter-1 social-signal analysis), `visual` (visual signals),
            and `audio` (the in-process audio tracks). Each selected group is
            gated by the server's `REALTIME_TRACKS` setting: a group the server
            has not enabled is rejected, and a selected group runs only the
            concrete tracks that `REALTIME_TRACKS` actually enables. When
            omitted, the default is `audio` + `visual` (not `video`), clamped to
            the groups the server allows; if none of those defaults are allowed,
            every allowed group is used so the session still analyzes. The
            values the server allows are advertised on `session.ready` under
            `supported_session_config_options.analysis_groups`.
          examples:
            - - audio
              - visual
          title: Analysis Groups
      title: Real-time Session Config
      type: object
    RealtimeSessionConfigV1Message:
      description: >-
        v1 real-time session-config message (chanx routing wrapper).


        Declared so the AsyncAPI generator surfaces the config schema on the

        ``/v0/realtime/analyze`` channel. The wire shape is the raw

        :class:`RealtimeSessionConfigV1` payload — chanx's
        ``action``/``payload``

        envelope is documentation-only and never appears on the wire.
      properties:
        action:
          const: realtime_session_config_v1
          default: realtime_session_config_v1
          title: Action
          type: string
        payload:
          $ref: '#/components/schemas/Real-time Session Config'
      required:
        - payload
      title: RealtimeSessionConfigV1Message
      type: object
    RealtimeSessionReadyConfigOptionsV1:
      description: >-
        Supported session-config options advertised on the real-time
        ``session.ready``.


        Mirrors the field names of :class:`RealtimeSessionConfigV1`. Unlike the
        stream

        options, the real-time endpoint advertises only its feedback controls
        and

        the analysis-group selection, and never the stream ``include`` /

        ``goal_dimensions`` options, which are not part of the real-time
        contract.
      properties:
        realtime_feedback_instructions:
          const: string
          default: string
          description: >-
            Accepted type for the ``realtime_feedback_instructions`` field of
            :class:`RealtimeSessionConfigV1`. It takes free-form text rather
            than an enumerable set of values, so its accepted JSON type
            (``string``) is advertised instead of a value list.
          examples:
            - string
          title: Realtime Feedback Instructions
          type: string
        realtime_feedback_frequency:
          description: >-
            Supported values for the ``realtime_feedback_frequency`` field of
            :class:`RealtimeSessionConfigV1`.
          examples:
            - - high
              - medium
              - low
          items:
            $ref: '#/components/schemas/RealtimeFeedbackFrequency'
          title: Realtime Feedback Frequency
          type: array
        analysis_groups:
          description: >-
            Analysis groups the caller may select for the ``analysis_groups``
            field of :class:`RealtimeSessionConfigV1`. Limited to the groups the
            current ``REALTIME_TRACKS`` setting enables, so a caller can
            discover the allowed surface at connect time without round-tripping
            a rejection.
          examples:
            - - video
              - visual
              - audio
          items:
            $ref: '#/components/schemas/AnalysisGroup'
          title: Analysis Groups
          type: array
      required:
        - realtime_feedback_frequency
        - analysis_groups
      title: Real-time Supported Session Config Options
      type: object
    RealtimeSessionReadyV1Data:
      description: >-
        Payload for the real-time ``session.ready`` event.


        Carries the same connection-level limits as the stream ``session.ready``
        but

        advertises the real-time session-config options
        (``realtime_feedback_instructions`` /

        ``realtime_feedback_frequency``) rather than the stream ``include`` /

        ``goal_dimensions`` options.
      properties:
        session_idle_timeout_seconds:
          description: >-
            Number of seconds the server allows the session to stay idle (no
            inbound frames) before it closes the connection with ``ih6003``. A
            value of ``0`` indicates the idle timeout is disabled for this
            session.
          examples:
            - 300
          minimum: 0
          title: Session Idle Timeout Seconds
          type: integer
        session_max_duration_seconds:
          description: >-
            Maximum total duration in seconds the server allows the session to
            remain open before closing the connection with ``ih6004``. A value
            of ``0`` indicates the maximum duration is disabled for this
            session.
          examples:
            - 3600
          minimum: 0
          title: Session Max Duration Seconds
          type: integer
        max_segment_duration_seconds:
          anyOf:
            - type: number
            - type: 'null'
          description: >-
            Maximum probed duration in seconds of a single inbound video chunk,
            or ``null`` when no fixed duration cap applies (the size cap in
            ``max_segment_size_bytes`` is the binding limit for long chunks).
          title: Max Segment Duration Seconds
        min_segment_size_bytes:
          description: >-
            Minimum size in bytes of a single inbound video chunk. Zero-byte
            frames are rejected and never reach analysis.
          examples:
            - 1
          minimum: 1
          title: Min Segment Size Bytes
          type: integer
        max_segment_size_bytes:
          description: >-
            Maximum size in bytes of a single inbound video chunk. Chunks larger
            than this are rejected with ``ih6002``.
          examples:
            - 33554432
          minimum: 1
          title: Max Segment Size Bytes
          type: integer
        supported_session_config_options:
          $ref: '#/components/schemas/Real-time Supported Session Config Options'
          description: >-
            Enumerates the values the server accepts on an inbound
            ``realtime_session_config_v1`` text frame.
      required:
        - session_idle_timeout_seconds
        - session_max_duration_seconds
        - min_segment_size_bytes
        - max_segment_size_bytes
        - supported_session_config_options
      title: RealtimeSessionReadyV1Data
      type: object
    RealtimeSessionReadyV1Message:
      description: v1 real-time ``session.ready`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: session.ready
          default: session.ready
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``session.ready``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/RealtimeSessionReadyV1Data'
          description: Per-event payload describing the session contract.
      required:
        - timestamp
        - data
      title: RealtimeSessionReadyV1Message
      type: object
    RealtimeSessionUpdatedV1Data:
      description: >-
        Payload for the real-time ``session.updated`` event.


        Carries the consolidated real-time session config that was just
        accepted, so

        the caller has a single source of truth for what the server will apply
        to

        subsequent feedback runs. Each successful inbound

        :class:`RealtimeSessionConfigV1` frame fully replaces the active config,
        so

        these values reflect the post-apply state of the session, not a delta
        against

        the previous config.


        Unlike the stream ``session.updated`` payload, this reports only the

        real-time session options (``realtime_feedback_instructions`` /
        ``realtime_feedback_frequency``

        / ``analysis_groups``) and never the stream-only ``include`` or

        ``goal_dimensions`` fields, which are not part of the real-time
        contract.
      properties:
        realtime_feedback_instructions:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The ``realtime_feedback_instructions`` after the config was applied,
            echoed back verbatim — ``null`` when none was set. Feedback is
            enabled only by a non-empty value (there is no default prompt), so a
            ``null``, empty, or whitespace-only value means feedback is disabled
            and no ``realtime_feedback.generated`` messages are emitted.
          examples:
            - >-
              Goal: help me close a sales call. Keep the guidance warm and
              concise.
          title: Realtime Feedback Instructions
        realtime_feedback_frequency:
          description: >-
            Active feedback frequency after the config was applied. ``null``
            when no ``realtime_feedback_frequency`` is set. The frequency only
            paces feedback once ``realtime_feedback_instructions`` has enabled
            it; without it, no ``realtime_feedback.generated`` messages are
            emitted regardless.
          examples:
            - medium
          $ref: '#/components/schemas/RealtimeFeedbackFrequency'
        analysis_groups:
          description: >-
            Active analysis groups after the config was applied — the effective
            selection actually in force for the session, already clamped to the
            groups the current ``REALTIME_TRACKS`` setting allows. Reflects the
            default (`audio` + `visual`, clamped) when the caller has not set
            ``analysis_groups``.
          examples:
            - - audio
              - visual
          items:
            $ref: '#/components/schemas/AnalysisGroup'
          title: Analysis Groups
          type: array
      title: RealtimeSessionUpdatedV1Data
      type: object
    RealtimeSessionUpdatedV1Message:
      description: v1 real-time ``session.updated`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: session.updated
          default: session.updated
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``session.updated``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/RealtimeSessionUpdatedV1Data'
          description: Per-event payload describing the accepted real-time session config.
      required:
        - timestamp
        - data
      title: RealtimeSessionUpdatedV1Message
      type: object
    RealtimeTranscriptSegment:
      description: >-
        One segment of a real-time transcript: a single diarized utterance.


        The same shape is used everywhere a transcript appears — the
        caller-supplied

        ``transcript.updated`` frames, the server-streamed
        ``transcript.generated``

        events, and the transcript handed to feedback — so the transcript has a

        single representation throughout.
      properties:
        start:
          description: Start time of the utterance, in seconds.
          examples:
            - 0.44
          title: Start
          type: number
        end:
          description: End time of the utterance, in seconds.
          examples:
            - 2.28
          title: End
          type: number
        text:
          description: The spoken text of this segment.
          examples:
            - Yeah, yeah, exactly.
          title: Text
          type: string
        speaker:
          description: Zero-based index identifying the speaker of this segment.
          examples:
            - 0
          title: Speaker
          type: integer
      required:
        - start
        - end
        - text
        - speaker
      title: Transcript Segment
      type: object
    Session Close:
      additionalProperties: false
      description: >-
        Inbound ``session.close`` text frame.


        Tells the server the caller is done sending video and wants a graceful

        end-of-analysis handshake: the server acknowledges with

        ``session.closing`` (carrying ``max_drain_seconds``), rejects any
        further

        binary video frames, finishes analyzing the already-accepted video and

        emits its normal result envelopes in order, emits final lifecycle

        envelopes for still-open analysis state, sends ``session.ended``, and

        closes the WebSocket. Unknown fields are rejected (with a non-fatal

        ``error`` envelope; the session stays open) so a caller typo cannot be

        silently misread as a close request.


        Only binary video is refused after acceptance. Text messages remain

        accepted while the session drains: a session-config update is applied

        and acknowledged as usual and governs the analysis still draining, a

        duplicate ``session.close`` is ignored, and (on the real-time endpoint)

        a ``transcript.updated`` still lands and is rendered into any real-time
        feedback

        that runs during the drain. Malformed text frames received during the

        drain are rejected with a non-fatal ``error`` envelope rather than

        closing the connection early, so the caller always gets its

        ``session.ended``.
      examples:
        - type: session.close
      properties:
        type:
          const: session.close
          description: >-
            Discriminator identifying the inbound message kind. For a close
            request it is always ``session.close``.
          title: Type
          type: string
      required:
        - type
      title: Session Close
      type: object
    Session Config:
      additionalProperties: false
      description: >-
        Optional caller-supplied session configuration. This message can be sent
        at any time to update the configuration.
      examples:
        - include:
            - conversation_quality_overall
      properties:
        include:
          description: >-
            Flags indicating which conversation quality sections to include in
            result messages.


            Accepted values:


            - `conversation_quality_overall`: periodically report the overall
            conversation quality scores, cumulative across all video processed
            so far in the session.

            - `conversation_quality_timeline`: periodically report the
            per-window conversation quality scores.


            When omitted, no optional sections are included. Unknown values are
            ignored.
          examples:
            - - conversation_quality_overall
          items:
            $ref: '#/components/schemas/IncludeFlag'
          title: Include
          type: array
      title: Session Config
      type: object
    SessionCloseV1:
      additionalProperties: false
      description: >-
        Inbound ``session.close`` text frame.


        Tells the server the caller is done sending video and wants a graceful

        end-of-analysis handshake: the server acknowledges with

        ``session.closing`` (carrying ``max_drain_seconds``), rejects any
        further

        binary video frames, finishes analyzing the already-accepted video and

        emits its normal result envelopes in order, emits final lifecycle

        envelopes for still-open analysis state, sends ``session.ended``, and

        closes the WebSocket. Unknown fields are rejected (with a non-fatal

        ``error`` envelope; the session stays open) so a caller typo cannot be

        silently misread as a close request.


        Only binary video is refused after acceptance. Text messages remain

        accepted while the session drains: a session-config update is applied

        and acknowledged as usual and governs the analysis still draining, a

        duplicate ``session.close`` is ignored, and (on the real-time endpoint)

        a ``transcript.updated`` still lands and is rendered into any real-time
        feedback

        that runs during the drain. Malformed text frames received during the

        drain are rejected with a non-fatal ``error`` envelope rather than

        closing the connection early, so the caller always gets its

        ``session.ended``.
      examples:
        - type: session.close
      properties:
        type:
          const: session.close
          description: >-
            Discriminator identifying the inbound message kind. For a close
            request it is always ``session.close``.
          title: Type
          type: string
      required:
        - type
      title: Session Close
      type: object
    SessionCloseV1Message:
      description: >-
        v1 ``session.close`` inbound message (chanx routing wrapper).


        Declared so the AsyncAPI generator can surface the close-request schema
        on

        the stream and real-time channels. The wire shape is the raw

        :class:`SessionCloseV1` payload — chanx's ``action``/``payload``
        envelope

        is documentation-only and never appears on the wire.
      properties:
        action:
          const: stream_session_close_v1
          default: stream_session_close_v1
          title: Action
          type: string
        payload:
          $ref: '#/components/schemas/Session Close'
      required:
        - payload
      title: SessionCloseV1Message
      type: object
    SessionClosingV1Data:
      description: |-
        Payload for the ``session.closing`` event.

        Carries the maximum time the caller should expect to wait between this
        acknowledgment and the final ``session.ended`` message + socket close.
      properties:
        max_drain_seconds:
          description: >-
            Maximum number of seconds the server will spend draining
            already-accepted analysis work before it closes the session. The
            session closes earlier when the accepted work finishes sooner; work
            still unfinished at this deadline is abandoned so the close is never
            delayed past it. Use this as the upper bound for a client-side wait
            on ``session.ended``.
          examples:
            - 60
          minimum: 0
          title: Max Drain Seconds
          type: integer
      required:
        - max_drain_seconds
      title: SessionClosingV1Data
      type: object
    SessionClosingV1Message:
      description: v1 ``session.closing`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: session.closing
          default: session.closing
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``session.closing``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/SessionClosingV1Data'
          description: Per-event payload describing the drain contract.
      required:
        - timestamp
        - data
      title: SessionClosingV1Message
      type: object
    SessionEndedReason:
      description: Why the server ended the analysis session.
      enum:
        - client_shutdown
      title: SessionEndedReason
      type: string
    SessionEndedV1Data:
      description: Payload for the ``session.ended`` event.
      properties:
        reason:
          $ref: '#/components/schemas/SessionEndedReason'
          description: >-
            Why the session ended. ``client_shutdown`` means the caller
            requested a graceful close with ``session.close`` and the server
            finished draining the accepted work.
          examples:
            - client_shutdown
      required:
        - reason
      title: SessionEndedV1Data
      type: object
    SessionEndedV1Message:
      description: v1 ``session.ended`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: session.ended
          default: session.ended
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``session.ended``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/SessionEndedV1Data'
          description: Per-event payload describing why the session ended.
      required:
        - timestamp
        - data
      title: SessionEndedV1Message
      type: object
    SessionReadyConfigOptionsV1:
      description: |-
        Supported session-config options advertised on ``session.ready``.

        Mirrors the field names of :class:`StreamSessionConfigV1`. Each list
        enumerates the values the server will accept on an inbound
        ``stream_session_config_v1`` text frame so a client can render UI or
        validate config locally without round-tripping rejections.
      properties:
        include:
          description: >-
            Supported values for the ``include`` field of
            :class:`StreamSessionConfigV1`.
          examples:
            - - conversation_quality_overall
              - conversation_quality_timeline
          items:
            $ref: '#/components/schemas/IncludeFlag'
          title: Include
          type: array
      required:
        - include
      title: SessionReadyConfigOptionsV1
      type: object
    SessionReadyV1Data:
      description: |-
        Payload for the ``session.ready`` event.

        Carries connection-level metadata describing the limits and supported
        configuration of the just-established session. Field values reflect
        the active server-side configuration at connect time; a session that
        spans a configuration change continues to be governed by the values
        reported here.
      properties:
        session_idle_timeout_seconds:
          description: >-
            Number of seconds the server allows the session to stay idle (no
            inbound frames) before it closes the connection with ``ih6003``. A
            value of ``0`` indicates the idle timeout is disabled for this
            session.
          examples:
            - 300
          minimum: 0
          title: Session Idle Timeout Seconds
          type: integer
        session_max_duration_seconds:
          description: >-
            Maximum total duration in seconds the server allows the session to
            remain open before closing the connection with ``ih6004``. A value
            of ``0`` indicates the maximum duration is disabled for this
            session.
          examples:
            - 3600
          minimum: 0
          title: Session Max Duration Seconds
          type: integer
        max_segment_duration_seconds:
          anyOf:
            - type: number
            - type: 'null'
          description: >-
            Maximum probed duration in seconds of a single inbound video chunk,
            or ``null`` when no fixed duration cap applies (the size cap in
            ``max_segment_size_bytes`` is the binding limit for long chunks).
          title: Max Segment Duration Seconds
        min_segment_size_bytes:
          description: >-
            Minimum size in bytes of a single inbound video chunk. Zero-byte
            frames are rejected and never reach analysis.
          examples:
            - 1
          minimum: 1
          title: Min Segment Size Bytes
          type: integer
        max_segment_size_bytes:
          description: >-
            Maximum size in bytes of a single inbound video chunk. Chunks larger
            than this are rejected with ``ih6002``.
          examples:
            - 33554432
          minimum: 1
          title: Max Segment Size Bytes
          type: integer
        supported_session_config_options:
          $ref: '#/components/schemas/SessionReadyConfigOptionsV1'
          description: >-
            Enumerates the values the server accepts on an inbound
            ``stream_session_config_v1`` text frame.
      required:
        - session_idle_timeout_seconds
        - session_max_duration_seconds
        - min_segment_size_bytes
        - max_segment_size_bytes
        - supported_session_config_options
      title: SessionReadyV1Data
      type: object
    SessionReadyV1Message:
      description: v1 ``session.ready`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: session.ready
          default: session.ready
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``session.ready``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/SessionReadyV1Data'
          description: Per-event payload describing the session contract.
      required:
        - timestamp
        - data
      title: SessionReadyV1Message
      type: object
    SessionUpdatedV1Data:
      description: |-
        Payload for the ``session.updated`` event.

        Carries the consolidated session config that was just accepted, so
        the caller has a single source of truth for what the server will
        apply to subsequent analysis windows. Each successful inbound
        :class:`StreamSessionConfigV1` frame fully replaces the active
        config — ``include`` here reflects the post-apply state of the
        session, not a delta against the previous config.
      properties:
        include:
          description: >-
            Active opt-in conversation quality sub-sections after the config was
            applied. Empty when no CQI sections are requested.
          examples:
            - - conversation_quality_overall
          items:
            $ref: '#/components/schemas/IncludeFlag'
          title: Include
          type: array
      required:
        - include
      title: SessionUpdatedV1Data
      type: object
    SessionUpdatedV1Message:
      description: v1 ``session.updated`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: session.updated
          default: session.updated
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``session.updated``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/SessionUpdatedV1Data'
          description: Per-event payload describing the accepted session config.
      required:
        - timestamp
        - data
      title: SessionUpdatedV1Message
      type: object
    SignalDetectedV1Data:
      description: |-
        Payload for the ``signal.detected`` event.

        Carries only a start time — no window end — because the envelope marks
        the moment the signal transitions from inactive to active. The matching
        ``signal.ended`` envelope reports the end-time when the signal stops
        being detected.
      properties:
        signal_type:
          $ref: '#/components/schemas/SignalType'
          description: The detected social signal (e.g. 'agreement', 'confusion').
          examples:
            - agreement
        start:
          description: >-
            Time at which the signal first becomes active, in seconds, in
            absolute session-cumulative time.
          examples:
            - 3
          title: Start
          type: number
        probability:
          description: 'Confidence level of the detected signal: high, medium, or low.'
          examples:
            - high
          $ref: '#/components/schemas/Probability'
        rationale:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            A concise, evidence-based explanation of why the signal was
            detected. Grounded in observable cues from the video.
          examples:
            - Subject nodded repeatedly while maintaining eye contact.
          title: Rationale
        modality:
          description: >-
            Analysis modalities used to detect this signal. Contains 'audio'
            and/or 'video' depending on which tracks detected the signal. When
            multiple tracks of different modalities detect the same signal, both
            modalities are included.
          examples:
            - - audio
              - video
          items:
            type: string
          title: Modality
          type: array
      required:
        - signal_type
        - start
      title: SignalDetectedV1Data
      type: object
    SignalDetectedV1Message:
      description: v1 ``signal.detected`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: signal.detected
          default: signal.detected
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``signal.detected``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/SignalDetectedV1Data'
          description: Per-event payload describing the detected signal.
      required:
        - timestamp
        - data
      title: SignalDetectedV1Message
      type: object
    SignalEndedV1Data:
      description: |-
        Payload for the ``signal.ended`` event.

        Carries only an end time — no start or window — because the envelope
        marks the moment the signal transitions from active to inactive. The
        matching ``signal.detected`` envelope reported the start-time when the
        signal became active.
      properties:
        signal_type:
          $ref: '#/components/schemas/SignalType'
          description: The social signal that is no longer active.
          examples:
            - agreement
        end:
          description: >-
            Time at which the signal stopped being active, in seconds, in
            absolute session-cumulative time.
          examples:
            - 14
          title: End
          type: number
      required:
        - signal_type
        - end
      title: SignalEndedV1Data
      type: object
    SignalEndedV1Message:
      description: v1 ``signal.ended`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: signal.ended
          default: signal.ended
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``signal.ended``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/SignalEndedV1Data'
          description: Per-event payload describing the ended signal.
      required:
        - timestamp
        - data
      title: SignalEndedV1Message
      type: object
    SignalType:
      description: Enumeration of supported social signals.
      enum:
        - agreement
        - confidence
        - confusion
        - disagreement
        - disengagement
        - engagement
        - frustration
        - hesitation
        - interest
        - skepticism
        - stress
        - uncertainty
      title: SignalType
      type: string
    SignalUpdatedV1Data:
      description: |-
        Payload for the ``signal.updated`` event.

        Emitted while the signal remains active and its ``probability`` has
        changed since the most recently emitted envelope for the same
        ``signal_type``. Carries the same fields as ``signal.detected``:
        ``start`` is the moment from which the new probability applies.
      properties:
        signal_type:
          $ref: '#/components/schemas/SignalType'
          description: The signal whose probability changed.
          examples:
            - agreement
        start:
          description: >-
            Time at which the new probability begins to apply, in seconds, in
            absolute session-cumulative time.
          examples:
            - 6
          title: Start
          type: number
        probability:
          description: 'Updated confidence level of the signal: high, medium, or low.'
          examples:
            - medium
          $ref: '#/components/schemas/Probability'
        rationale:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            A concise, evidence-based explanation of why the signal was detected
            at its new probability. Grounded in observable cues from the video.
          examples:
            - Subject nodded once but then looked away.
          title: Rationale
        modality:
          description: >-
            Analysis modalities used to detect this signal. Contains 'audio'
            and/or 'video' depending on which tracks detected the signal.
          examples:
            - - audio
              - video
          items:
            type: string
          title: Modality
          type: array
      required:
        - signal_type
        - start
      title: SignalUpdatedV1Data
      type: object
    SignalUpdatedV1Message:
      description: v1 ``signal.updated`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: signal.updated
          default: signal.updated
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``signal.updated``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/SignalUpdatedV1Data'
          description: Per-event payload describing the updated probability.
      required:
        - timestamp
        - data
      title: SignalUpdatedV1Message
      type: object
    StreamErrorV1Data:
      description: Payload for the ``error`` event.
      properties:
        code:
          description: Machine-readable error code (e.g. 'ih2001').
          examples:
            - ih6002
          title: Code
          type: string
        message:
          description: >-
            Error explanation. Contains any additional details about the
            specific error that was encountered.
          title: Message
          type: string
        link:
          anyOf:
            - type: string
            - type: 'null'
          description: URL to additional information about this error.
          title: Link
        segment:
          anyOf:
            - type: integer
            - type: 'null'
          description: >-
            The incoming caller segment associated with this error, when
            applicable. ``null`` for errors that are not tied to one specific
            caller segment.
          title: Segment
      required:
        - code
        - message
      title: StreamErrorV1Data
      type: object
    StreamErrorV1Message:
      description: v1 ``error`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: error
          default: error
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``error``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/StreamErrorV1Data'
          description: Per-event payload describing the error.
      required:
        - timestamp
        - data
      title: StreamErrorV1Message
      type: object
    StreamSessionConfigV1:
      additionalProperties: false
      description: >-
        Optional caller-supplied session configuration. This message can be sent
        at any time to update the configuration.
      examples:
        - include:
            - conversation_quality_overall
      properties:
        include:
          description: >-
            Flags indicating which conversation quality sections to include in
            result messages.


            Accepted values:


            - `conversation_quality_overall`: periodically report the overall
            conversation quality scores, cumulative across all video processed
            so far in the session.

            - `conversation_quality_timeline`: periodically report the
            per-window conversation quality scores.


            When omitted, no optional sections are included. Unknown values are
            ignored.
          examples:
            - - conversation_quality_overall
          items:
            $ref: '#/components/schemas/IncludeFlag'
          title: Include
          type: array
      title: Session Config
      type: object
    StreamSessionConfigV1Message:
      description: |-
        v1 session-config message (chanx routing wrapper).

        Declared so the AsyncAPI generator can surface the config schema on the
        ``/v1/stream/analyze`` channel. The wire shape is the raw
        :class:`StreamSessionConfigV1` payload — chanx's ``action``/``payload``
        envelope is documentation-only and never appears on the wire.
      properties:
        action:
          const: stream_session_config_v1
          default: stream_session_config_v1
          title: Action
          type: string
        payload:
          $ref: '#/components/schemas/Session Config'
      required:
        - payload
      title: StreamSessionConfigV1Message
      type: object
    StreamVideoMessage:
      description: Message for streaming video.
      properties:
        action:
          const: stream_video
          default: stream_video
          title: Action
          type: string
        payload:
          title: Payload
        bytes:
          title: Bytes
          type: integer
      required:
        - payload
        - bytes
      title: StreamVideoMessage
      type: object
    Transcript Segment:
      description: >-
        One segment of a real-time transcript: a single diarized utterance.


        The same shape is used everywhere a transcript appears — the
        caller-supplied

        ``transcript.updated`` frames, the server-streamed
        ``transcript.generated``

        events, and the transcript handed to feedback — so the transcript has a

        single representation throughout.
      properties:
        start:
          description: Start time of the utterance, in seconds.
          examples:
            - 0.44
          title: Start
          type: number
        end:
          description: End time of the utterance, in seconds.
          examples:
            - 2.28
          title: End
          type: number
        text:
          description: The spoken text of this segment.
          examples:
            - Yeah, yeah, exactly.
          title: Text
          type: string
        speaker:
          description: Zero-based index identifying the speaker of this segment.
          examples:
            - 0
          title: Speaker
          type: integer
      required:
        - start
        - end
        - text
        - speaker
      title: Transcript Segment
      type: object
    Transcript Update:
      description: >-
        Inbound ``transcript.updated`` text frame.


        Lets the caller provide (and update) a transcript during the session.
        The

        ``transcript`` payload is a list of :class:`RealtimeTranscriptSegment`

        (``{start, end, text, speaker}``) entries; the most recent value is
        stored

        for the session and rendered into the feedback prompt.
      examples:
        - transcript:
            - end: 2.28
              speaker: 0
              start: 0.44
              text: Yeah, yeah, exactly.
            - end: 5.88
              speaker: 0
              start: 3
              text: Um I think that that makes sense.
          type: transcript.updated
      properties:
        type:
          const: transcript.updated
          default: transcript.updated
          description: >-
            Discriminator identifying the inbound message kind. For a transcript
            update it is always ``transcript.updated``.
          title: Type
          type: string
        transcript:
          description: >-
            Caller-supplied transcript as a list of ``{start, end, text,
            speaker}`` segments, in spoken order. The most recent value is
            stored for the session and rendered into the feedback prompt.
          items:
            $ref: '#/components/schemas/RealtimeTranscriptSegment'
          title: Transcript
          type: array
      required:
        - transcript
      title: Transcript Update
      type: object
    TranscriptGeneratedV1Message:
      description: v1 ``transcript.generated`` envelope (chanx routing wrapper).
      properties:
        timestamp:
          description: ISO 8601 timestamp identifying when the event occurred.
          examples:
            - '2025-01-01T00:00:00.000000Z'
          title: Timestamp
          type: string
        correlation_id:
          default: ''
          description: >-
            Unique identifier assigned to this WebSocket connection. Use it when
            contacting support to locate the relevant records.
          title: Correlation Id
          type: string
        type:
          const: transcript.generated
          default: transcript.generated
          description: >-
            Discriminator identifying the message kind. For this message it is
            always ``transcript.generated``.
          title: Type
          type: string
        data:
          $ref: '#/components/schemas/Transcript Segment'
          description: The newly-finalized transcript segment for this interval.
      required:
        - timestamp
        - data
      title: TranscriptGeneratedV1Message
      type: object
    TranscriptUpdatedV1:
      description: >-
        Inbound ``transcript.updated`` text frame.


        Lets the caller provide (and update) a transcript during the session.
        The

        ``transcript`` payload is a list of :class:`RealtimeTranscriptSegment`

        (``{start, end, text, speaker}``) entries; the most recent value is
        stored

        for the session and rendered into the feedback prompt.
      examples:
        - transcript:
            - end: 2.28
              speaker: 0
              start: 0.44
              text: Yeah, yeah, exactly.
            - end: 5.88
              speaker: 0
              start: 3
              text: Um I think that that makes sense.
          type: transcript.updated
      properties:
        type:
          const: transcript.updated
          default: transcript.updated
          description: >-
            Discriminator identifying the inbound message kind. For a transcript
            update it is always ``transcript.updated``.
          title: Type
          type: string
        transcript:
          description: >-
            Caller-supplied transcript as a list of ``{start, end, text,
            speaker}`` segments, in spoken order. The most recent value is
            stored for the session and rendered into the feedback prompt.
          items:
            $ref: '#/components/schemas/RealtimeTranscriptSegment'
          title: Transcript
          type: array
      required:
        - transcript
      title: Transcript Update
      type: object
    TranscriptUpdatedV1Message:
      description: v1 ``transcript.updated`` inbound message (chanx routing wrapper).
      properties:
        action:
          const: realtime_transcript_updated_v1
          default: realtime_transcript_updated_v1
          title: Action
          type: string
        payload:
          $ref: '#/components/schemas/Transcript Update'
      required:
        - payload
      title: TranscriptUpdatedV1Message
      type: object
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        API key authentication. Include your API key in the Authorization header
        as 'Bearer <api_key>'.
