Cartesia TTS WebSocket API

Bidirectional, multiplexed WebSocket at wss://api.cartesia.ai/tts/websocket for realtime speech generation. Clients send JSON generation requests keyed by a context_id (continuing a context preserves prosody across chunks of transcript) and receive base64-encoded audio chunks, optional word and phoneme timestamps, flush acknowledgements, and a final done message. A single connection scales to dozens of concurrent generation contexts.

AsyncAPI Specification

cartesia-ai-asyncapi.yml Raw ↑
asyncapi: '2.6.0'
id: 'urn:com:cartesia:api:v1:websocket'
info:
  title: Cartesia Realtime WebSocket API (TTS + STT)
  version: '2026-03-01'
  description: |
    AsyncAPI 2.6 description of Cartesia's **documented public WebSocket API**.
    Unlike most providers in this catalog, Cartesia publishes a real,
    bidirectional WebSocket protocol - not Server-Sent Events - for its two
    core realtime audio surfaces:

    - **Text-to-Speech WebSocket** at `wss://api.cartesia.ai/tts/websocket`
      (https://docs.cartesia.ai/api-reference/tts/websocket): a multiplexed,
      bidirectional connection where clients send generation requests keyed
      by a `context_id` and receive base64-encoded audio chunks, word/phoneme
      timestamps, flush acknowledgements, and completion/error messages. A
      single connection scales to dozens of concurrent generation contexts.
    - **Speech-to-Text WebSocket** at `wss://api.cartesia.ai/stt/websocket`
      (https://docs.cartesia.ai/api-reference/stt/websocket): clients stream
      raw binary audio and receive incremental and final transcript messages.
      A companion "Auto" variant at `/stt/turns/websocket`
      (https://docs.cartesia.ai/api-reference/stt/turns/websocket) adds
      built-in turn detection so the server itself decides when an utterance
      ends, instead of the client issuing manual `finalize` commands.

    Both protocols authenticate with either an `X-API-Key` header or an
    `access_token` query parameter (for browser clients that cannot set
    custom headers), plus a `cartesia_version` query parameter.

    REST equivalents (single-shot bytes and Server-Sent Events) for both TTS
    and STT are modeled separately in the companion OpenAPI document at
    `openapi/cartesia-ai-openapi.yml`; SSE there is one-way HTTP streaming and
    is not part of this WebSocket document.
  contact:
    name: API Evangelist
    email: kin@apievangelist.com
    url: https://apievangelist.com
  license:
    name: API documentation - Cartesia Terms of Service
    url: https://cartesia.ai/terms-of-service
  x-transport-notes:
    transport: WebSocket
    protocol: wss
    direction: bidirectional
    confirmed: true
    source:
      - https://docs.cartesia.ai/api-reference/tts/websocket
      - https://docs.cartesia.ai/api-reference/stt/websocket
      - https://docs.cartesia.ai/api-reference/stt/turns/websocket
defaultContentType: application/json
servers:
  ttsWebsocket:
    url: 'api.cartesia.ai/tts/websocket?cartesia_version=2026-03-01'
    protocol: wss
    description: |
      Bidirectional TTS streaming connection. Authenticate with an
      `X-API-Key` header or an `access_token` query parameter.
    security:
      - apiKeyHeader: []
      - accessTokenQuery: []
  sttWebsocket:
    url: 'api.cartesia.ai/stt/websocket?model=ink-whisper&encoding=pcm_s16le&sample_rate=16000&cartesia_version=2026-03-01'
    protocol: wss
    description: |
      Realtime, manual-finalization speech-to-text connection. Query params
      `model`, `encoding`, `sample_rate`, and `cartesia_version` are required.
      An "Auto" variant with built-in turn detection is available at the same
      host under `/stt/turns/websocket`.
    security:
      - apiKeyHeader: []
      - accessTokenQuery: []
channels:
  /tts/websocket:
    servers:
      - ttsWebsocket
    description: |
      Multiplexed realtime TTS generation. The client opens one WebSocket and
      may run many concurrent generations, each identified by a unique
      `context_id`. Sending additional messages with `continue: true` on the
      same `context_id` extends that context's generation while preserving
      prosody. A `cancel: true` message stops a context's generation early.
    bindings:
      ws:
        bindingVersion: '0.1.0'
    publish:
      operationId: sendTtsGenerationRequest
      summary: Send a TTS generation (or cancel) request.
      description: |
        JSON text message. A generation request must include `model_id`,
        `transcript`, `voice`, `output_format`, and `context_id`. A cancel
        request includes only `context_id` and `cancel: true`.
      message:
        oneOf:
          - $ref: '#/components/messages/TtsGenerationRequest'
          - $ref: '#/components/messages/TtsCancelRequest'
    subscribe:
      operationId: receiveTtsStreamEvents
      summary: Receive audio chunks, timestamps, and control messages for a context.
      description: |
        Every server message carries the `context_id` it corresponds to, so
        clients can demultiplex responses across concurrently running
        generations on the same connection.
      message:
        oneOf:
          - $ref: '#/components/messages/TtsAudioChunk'
          - $ref: '#/components/messages/TtsWordTimestamps'
          - $ref: '#/components/messages/TtsPhonemeTimestamps'
          - $ref: '#/components/messages/TtsFlushDone'
          - $ref: '#/components/messages/TtsDone'
          - $ref: '#/components/messages/TtsError'
  /stt/websocket:
    servers:
      - sttWebsocket
    description: |
      Realtime speech-to-text without automatic turn detection. The client
      streams binary audio frames (100ms chunks recommended) and sends text
      commands (`finalize`, `close`) to control finalization; the server
      returns incremental and final transcript messages. The connection-level
      query parameters `model`, `encoding`, and `sample_rate` are required and
      cannot be changed mid-connection. The `/stt/turns/websocket` variant
      (not separately channeled here) accepts the same audio and message
      shapes but adds server-driven turn detection so `finalize` is optional.
    bindings:
      ws:
        bindingVersion: '0.1.0'
    publish:
      operationId: sendSttAudioAndCommands
      summary: Stream binary audio frames and send finalize/close commands.
      message:
        oneOf:
          - $ref: '#/components/messages/SttAudioFrame'
          - $ref: '#/components/messages/SttFinalizeCommand'
          - $ref: '#/components/messages/SttCloseCommand'
    subscribe:
      operationId: receiveSttTranscripts
      summary: Receive incremental/final transcripts and control messages.
      message:
        oneOf:
          - $ref: '#/components/messages/SttTranscript'
          - $ref: '#/components/messages/SttFlushDone'
          - $ref: '#/components/messages/SttDone'
          - $ref: '#/components/messages/SttError'
components:
  securitySchemes:
    apiKeyHeader:
      type: httpApiKey
      name: X-API-Key
      in: header
      description: Standard Cartesia API key (sk_car_...), sent as a header when opening the WebSocket connection.
    accessTokenQuery:
      type: userPassword
      description: |
        Short-lived access token (minted via POST /access-token) passed as the
        `access_token` query parameter, for browser clients that cannot set
        custom headers on a WebSocket handshake.
  messages:
    TtsGenerationRequest:
      name: TtsGenerationRequest
      title: TTS generation request
      contentType: application/json
      payload:
        $ref: '#/components/schemas/TtsGenerationRequestPayload'
      examples:
        - name: basicGeneration
          payload:
            model_id: sonic-3.5
            transcript: 'Hello, world!'
            voice:
              mode: id
              id: a0e99841-438c-4a64-b679-ae501e7d6091
            output_format:
              container: raw
              encoding: pcm_s16le
              sample_rate: 16000
            context_id: unique-context-identifier
            language: en
            continue: false
            max_buffer_delay_ms: 3000
            add_timestamps: false
            add_phoneme_timestamps: false
    TtsCancelRequest:
      name: TtsCancelRequest
      title: TTS cancel request
      contentType: application/json
      payload:
        $ref: '#/components/schemas/TtsCancelRequestPayload'
      examples:
        - name: cancel
          payload:
            context_id: context-to-cancel
            cancel: true
    TtsAudioChunk:
      name: TtsAudioChunk
      title: Streamed audio chunk
      contentType: application/json
      payload:
        $ref: '#/components/schemas/TtsAudioChunkPayload'
      examples:
        - name: chunk
          payload:
            type: chunk
            data: base64-encoded-audio-data
            done: false
            status_code: 206
            step_time: 123
            context_id: context-id
    TtsWordTimestamps:
      name: TtsWordTimestamps
      title: Word-level timestamps
      contentType: application/json
      payload:
        $ref: '#/components/schemas/TtsWordTimestampsPayload'
      examples:
        - name: timestamps
          payload:
            type: timestamps
            done: false
            status_code: 206
            context_id: context-id
            word_timestamps:
              words: [Hello, world]
              start: [0, 0.5]
              end: [0.4, 0.9]
    TtsPhonemeTimestamps:
      name: TtsPhonemeTimestamps
      title: Phoneme-level timestamps
      contentType: application/json
      payload:
        $ref: '#/components/schemas/TtsPhonemeTimestampsPayload'
      examples:
        - name: phonemeTimestamps
          payload:
            type: phoneme_timestamps
            done: false
            status_code: 206
            context_id: context-id
            phoneme_timestamps:
              phonemes: [h, "ə", l]
              start: [0.093, 0.174, 0.255]
              end: [0.174, 0.255, 0.337]
    TtsFlushDone:
      name: TtsFlushDone
      title: Flush acknowledgement
      contentType: application/json
      payload:
        $ref: '#/components/schemas/FlushDonePayload'
      examples:
        - name: flushDone
          payload:
            type: flush_done
            done: false
            flush_done: true
            flush_id: 1
            status_code: 206
            context_id: context-id
    TtsDone:
      name: TtsDone
      title: Generation completion signal
      contentType: application/json
      payload:
        $ref: '#/components/schemas/DonePayload'
      examples:
        - name: done
          payload:
            type: done
            done: true
            status_code: 206
            context_id: context-id
    TtsError:
      name: TtsError
      title: Error response
      contentType: application/json
      payload:
        $ref: '#/components/schemas/ErrorPayload'
      examples:
        - name: error
          payload:
            type: error
            done: true
            title: Invalid model
            message: The model is not valid...
            error_code: model_not_found
            status_code: 400
            doc_url: https://docs.cartesia.ai/api-reference/tts/websocket
            request_id: unique-request-id
            context_id: context-id
    SttAudioFrame:
      name: SttAudioFrame
      title: Binary audio frame
      contentType: application/octet-stream
      payload:
        type: string
        format: binary
        description: >-
          Raw audio bytes matching the connection's `encoding` and
          `sample_rate` query parameters, sent as a WebSocket binary frame.
          100ms chunks are recommended.
    SttFinalizeCommand:
      name: SttFinalizeCommand
      title: Finalize command
      contentType: text/plain
      payload:
        type: string
        enum:
          - finalize
        description: Text command instructing the server to transcribe currently buffered audio.
    SttCloseCommand:
      name: SttCloseCommand
      title: Close command
      contentType: text/plain
      payload:
        type: string
        enum:
          - close
        description: Text command instructing the server to flush remaining audio and terminate the session.
    SttTranscript:
      name: SttTranscript
      title: Transcript chunk
      contentType: application/json
      payload:
        $ref: '#/components/schemas/SttTranscriptPayload'
      examples:
        - name: partial
          payload:
            type: transcript
            is_final: false
            text: Hello wor
            words:
              - word: Hello
                start: 0
                end: 0.4
            request_id: req_01jbd6g2qdfw2adyrt2az8hz4w
        - name: final
          payload:
            type: transcript
            is_final: true
            text: Hello world
            words:
              - word: Hello
                start: 0
                end: 0.4
              - word: world
                start: 0.5
                end: 0.9
            request_id: req_01jbd6g2qdfw2adyrt2az8hz4w
    SttFlushDone:
      name: SttFlushDone
      title: Finalize acknowledgement
      contentType: application/json
      payload:
        $ref: '#/components/schemas/FlushDonePayload'
    SttDone:
      name: SttDone
      title: Close acknowledgement
      contentType: application/json
      payload:
        $ref: '#/components/schemas/DonePayload'
    SttError:
      name: SttError
      title: Error response
      contentType: application/json
      payload:
        $ref: '#/components/schemas/ErrorPayload'
  schemas:
    TtsGenerationRequestPayload:
      type: object
      required:
        - model_id
        - transcript
        - voice
        - output_format
        - context_id
      properties:
        model_id:
          type: string
          enum: [sonic-3.5, sonic-3, sonic-latest]
        transcript:
          type: string
        voice:
          type: object
          required: [mode, id]
          properties:
            mode:
              type: string
              enum: [id]
            id:
              type: string
              format: uuid
        output_format:
          type: object
          required: [container, encoding, sample_rate]
          properties:
            container:
              type: string
              enum: [raw]
            encoding:
              type: string
              enum: [pcm_f32le, pcm_s16le, pcm_mulaw, pcm_alaw]
            sample_rate:
              type: integer
              enum: [8000, 16000, 22050, 24000, 44100, 48000]
        context_id:
          type: string
          description: Unique identifier correlating requests/responses and preserving prosody across continued chunks.
        language:
          type: string
          description: One of 40+ supported language codes.
        continue:
          type: boolean
          default: false
          description: Set true if more transcript chunks follow on this context_id; false on the final chunk.
        flush:
          type: boolean
          description: Trigger a context flush.
        max_buffer_delay_ms:
          type: integer
          minimum: 0
          maximum: 5000
          default: 3000
        add_timestamps:
          type: boolean
          default: false
        add_phoneme_timestamps:
          type: boolean
          default: false
        pronunciation_dict_id:
          type: string
          nullable: true
        generation_config:
          type: object
          properties:
            volume:
              type: number
              minimum: 0.5
              maximum: 2.0
              default: 1
            speed:
              type: number
              minimum: 0.6
              maximum: 1.5
              default: 1
            emotion:
              type: string
              enum: [neutral, calm, angry, content, sad]
    TtsCancelRequestPayload:
      type: object
      required:
        - context_id
        - cancel
      properties:
        context_id:
          type: string
        cancel:
          type: boolean
          enum: [true]
    TtsAudioChunkPayload:
      type: object
      required:
        - type
        - data
        - context_id
      properties:
        type:
          type: string
          enum: [chunk]
        data:
          type: string
          description: Base64-encoded audio data.
        done:
          type: boolean
        status_code:
          type: integer
        step_time:
          type: integer
          description: Milliseconds taken to generate this chunk.
        context_id:
          type: string
    TtsWordTimestampsPayload:
      type: object
      required:
        - type
        - context_id
      properties:
        type:
          type: string
          enum: [timestamps]
        done:
          type: boolean
        status_code:
          type: integer
        context_id:
          type: string
        word_timestamps:
          type: object
          properties:
            words:
              type: array
              items:
                type: string
            start:
              type: array
              items:
                type: number
            end:
              type: array
              items:
                type: number
    TtsPhonemeTimestampsPayload:
      type: object
      required:
        - type
        - context_id
      properties:
        type:
          type: string
          enum: [phoneme_timestamps]
        done:
          type: boolean
        status_code:
          type: integer
        context_id:
          type: string
        phoneme_timestamps:
          type: object
          properties:
            phonemes:
              type: array
              items:
                type: string
            start:
              type: array
              items:
                type: number
            end:
              type: array
              items:
                type: number
    FlushDonePayload:
      type: object
      required:
        - type
        - context_id
      properties:
        type:
          type: string
          enum: [flush_done]
        done:
          type: boolean
        flush_done:
          type: boolean
        flush_id:
          type: integer
          description: Increments with each flush command, correlating with transcript batches.
        status_code:
          type: integer
        context_id:
          type: string
    DonePayload:
      type: object
      required:
        - type
        - done
        - context_id
      properties:
        type:
          type: string
          enum: [done]
        done:
          type: boolean
          enum: [true]
        status_code:
          type: integer
        context_id:
          type: string
    ErrorPayload:
      type: object
      required:
        - type
        - error_code
        - status_code
      properties:
        type:
          type: string
          enum: [error]
        done:
          type: boolean
        title:
          type: string
        message:
          type: string
        error_code:
          type: string
        status_code:
          type: integer
        doc_url:
          type: string
        request_id:
          type: string
        context_id:
          type: string
    SttTranscriptPayload:
      type: object
      required:
        - type
        - is_final
        - text
      properties:
        type:
          type: string
          enum: [transcript]
        is_final:
          type: boolean
          description: Whether this chunk represents a finalized segment of the transcript.
        text:
          type: string
          description: Delta text since the last finalized chunk.
        words:
          type: array
          items:
            type: object
            properties:
              word:
                type: string
              start:
                type: number
              end:
                type: number
        request_id:
          type: string
x-maintainers:
  - FN: Kin Lane
    email: kin@apievangelist.com