Skip to main content
This guide covers migrating from Deepgram’s Turn-based Audio (Flux) API. Both Cartesia and Deepgram Flux emit turn-based events over a WebSocket, so migrating to Ink is mostly a matter of renaming fields and updating a few connection parameters.

Back to guides

Other ways to migrate and best practices for Cartesia Speech-to-Text
This guide contains both bare API descriptions and SDK code. To install the SDK:
pip install cartesia
If you’re already using the Cartesia SDK, upgrade to version >=3.2.0
Ink 2 only supports English right now.
We expect to add more languages in the coming months.

Connection

Replace the Deepgram WebSocket URL and auth header with Cartesia’s.
- wss://api.deepgram.com/v2/listen?model=flux-general-en&encoding=linear16&sample_rate=16000
+ wss://api.cartesia.ai/stt/turns/websocket?model=ink-2&encoding=pcm_s16le&sample_rate=16000
- Authorization: Token <DEEPGRAM_API_KEY>
+ Authorization: Bearer <CARTESIA_API_KEY>
+ Cartesia-Version: 2026-03-01
In browsers, WebSockets do not support request headers. Instead, pass the API version as the cartesia_version query param and use a short-lived access token using the access_token query param instead of an API key. Connect to the turn-detection WebSocket with the Cartesia SDK:
import os
from cartesia import AsyncCartesia

client = AsyncCartesia(api_key=os.getenv("CARTESIA_API_KEY"))

async with client.stt.auto_finalize.websocket(
    model="ink-2", encoding="pcm_s16le", sample_rate=16000
) as connection:
    ...

Query parameters

Deepgram FluxCartesia InkNotes
model=flux-general-en requiredmodel=ink-2 requiredSee STT Models for all options.
encoding=linear16encoding=pcm_s16le requiredSee encoding for all options.
sample_ratesample_rate requiredNo change.
language_hintOnly English is supported right now. Multi-lingual support is coming soon!
cartesia_version=2026-03-01 requiredSee API Conventions for details.
eager_eot_threshold, eot_threshold, eot_timeout_msTurn detection is controlled by the model. Configuration is coming soon!
keytermComing soon!
mip_opt_outControlled by your organization.
DeepgramCartesia
linear16pcm_s16le
linear32pcm_s32le
mulawpcm_mulaw
alawpcm_alaw
Not supportedpcm_f16le
Not supportedpcm_f32le
opusNot supported
ogg-opusNot supported

Sending audio

Both APIs accept raw PCM audio as binary WebSocket frames in the same way.
Cartesia does not support these encodings: opus, ogg-opus
To close the session, send a JSON encoded WebSocket text frame:
- { "type": "CloseStream" }
+ { "type": "close" }
Cartesia has no equivalent of Deepgram’s Configure control message since there’s no need to configure end-of-turn.
# Equivalent to 
# deepgram_connection.send_media(audio_chunk)
await connection.send_raw(audio_chunk)

# Equivalent to
# deepgram_connection.send_close_stream()
await connection.send({"type": "close"})

Event mapping

Deepgram typeCartesia type
Connectedconnected
Errorerror
TurnInfoSee below
Deepgram wraps all turn events in a single TurnInfo message with an event discriminator. Cartesia emits one message type per event, with the type on the top-level type field.
Deepgram TurnInfo.eventCartesia typeCarries transcript?
StartOfTurnturn.startNo (Deepgram: yes)
Updateturn.updateYes
EagerEndOfTurnturn.eager_endYes
TurnResumedturn.resumeNo (Deepgram: yes)
EndOfTurnturn.endYes
A Deepgram TurnInfo message:
{
  "type": "TurnInfo",
  "event": "EndOfTurn",
  "turn_index": 0,
  "transcript": "Hi I need to cancel my subscription please.",
  "words": [...],
  "end_of_turn_confidence": 0.7,
  "audio_window_start": 0.0,
  "audio_window_end": 1.7
}
Becomes a Cartesia turn.* event:
{
  "type": "turn.end",
  "transcript": "Hi I need to cancel my subscription please.",
  "request_id": "2ff8af53-4d38-479d-8287-58940f01c701"
}
Like Deepgram, the transcript is cumulative within a turn.

Event handler

The branching structure of your handler is unchanged — just the message shape.
  ws.onmessage = (message) => {
    const data = JSON.parse(message.data);
-   if (data.type !== "TurnInfo") return;
-   switch (data.event) {
-     case "StartOfTurn":    onTurnStart(); break;
-     case "Update":         onTranscriptUpdate(data.transcript); break;
-     case "EagerEndOfTurn": prepareReply(data.transcript); break;
-     case "TurnResumed":    cancelReply(); break;
-     case "EndOfTurn":      finalizeReply(data.transcript); break;
-   }
+   switch (data.type) {
+     case "turn.start":     onTurnStart(); break;
+     case "turn.update":    onTranscriptUpdate(data.transcript); break;
+     case "turn.eager_end": prepareReply(data.transcript); break;
+     case "turn.resume":    cancelReply(); break;
+     case "turn.end":       finalizeReply(data.transcript); break;
+   }
  };
import asyncio
from cartesia.types.stt import STTAutoFinalizeWebsocketResponse

def on_message(message: STTAutoFinalizeWebsocketResponse) -> None:
    if message.type == "turn.start":
        print("StartOfTurn")
    elif message.type == "turn.update":
        print(f"Update: {message.transcript}")
    elif message.type == "turn.eager_end":
        print(f"EagerEndOfTurn: {message.transcript}")
    elif message.type == "turn.resume":
        print("TurnResumed")
    elif message.type == "turn.end":
        print(f"EndOfTurn: {message.transcript}")
    elif message.type == "error":
        print(f"Error: {message.message}")

# Equivalent to
# deepgram_connection.on(EventType.MESSAGE, on_message)
connection.on("event", on_message)

# Equivalent to
# asyncio.create_task(deepgram_connection.start_listening())
recv_task = asyncio.create_task(connection.dispatch_events())

Example Server Messages

Flux’s transcripts are joined with spaces. Ink’s are not.
Deepgram FluxCartesia Realtime STT (Auto)
StartOfTurnturn.start
Update "Flux's transcripts"turn.update "Flux's transcripts"
EagerEndOfTurn "Flux's transcripts"turn.eager_end "Flux's transcripts"
TurnResumedturn.resume
Update "Flux's transcripts are joined with spaces."turn.update "Flux's transcripts are joined with spaces."
EagerEndOfTurn "Flux's transcripts are joined with spaces."turn.eager_end "Flux's transcripts are joined with spaces."
EndOfTurn "Flux's transcripts are joined with spaces."turn.end "Flux's transcripts are joined with spaces."
StartOfTurnturn.start
Update "Ink's are not."turn.update " Ink's are not."
EagerEndOfTurn "Ink's are not."turn.eager_end " Ink's are not."
EndOfTurn "Ink's are not."turn.end " Ink's are not."

References

API Reference

Cartesia Realtime STT (Auto)

Full Code Example

Using the Cartesia SDK