VOICE / migrate-from-openai-realtime

Voice

Migrate from OpenAI Realtime to Grok Speech to Speech

Migrate from OpenAI Realtime to Grok Speech to Speech

Point the existing Realtime client at https://api.x.ai/v1, swap the key, and pass a Grok voice model. Most event handling stays.

Base URL, key, model

OpenAI SDK:

import os
from openai import AsyncOpenAI

client = AsyncOpenAI(
    api_key=os.environ["XAI_API_KEY"],
    base_url="https://api.x.ai/v1",
)

async with client.realtime.connect(model="grok-voice-latest") as conn:
    await conn.session.update(session={
        "voice": "eve",
        "instructions": "You are a helpful assistant.",
        "turn_detection": {"type": "server_vad"},
    })

Raw WebSocket:

url = "wss://api.x.ai/v1/realtime?model=grok-voice-latest"
headers = {"Authorization": f"Bearer {os.environ['XAI_API_KEY']}"}
Model Notes
grok-voice-latest Alias for grok-voice-think-fast-2.0
grok-voice-think-fast-2.0 Current flagship
grok-voice-think-fast-1.0 Previous generation

Pin a versioned name in production. grok-voice-latest tracks the current recommended model.

On grok-voice-think-fast-2.0, shorten the system prompt, drop GPT workaround lines, and leave reasoning.effort at the default "high" unless you set "none" to turn reasoning off.

Event name change

OpenAI conversation.item.input_audio_transcription.delta is conversation.item.input_audio_transcription.updated on xAI. The payload is the cumulative transcript (later updates may correct earlier text). It fires only when audio.input.transcription.model is "grok-transcribe".

Unsupported OpenAI events

Client → server: conversation.item.retrieve. output_audio_buffer.clear is WebRTC/SIP only.

Server → client (not emitted): conversation.item.done, conversation.item.input_audio_transcription.failed, conversation.item.input_audio_transcription.segment, conversation.item.retrieved, rate_limits.updated. output_audio_buffer.started / stopped / cleared are WebRTC/SIP only.

xAI-only fields

Feature Where What it does
force_message conversation.item.create item type TTS a scripted line with no model turn
resumption session.update Cache turns and replay on reconnect
replace session.update Spoken pronunciation map; transcript stays original

Browser sockets cannot send an Authorization header — mint an ephemeral token and pass xai-client-secret.{token} as the WebSocket protocol.

Pitfalls

  • Keep base_url / baseURL on the OpenAI SDK client so OpenAIRealtimeWS hits api.x.ai, not api.openai.com.
  • Do not port GPT prompt hacks onto grok-voice-think-fast-2.0.
  • Console API credits are separate from SuperGrok's weekly pool on grok.com.