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/baseURLon the OpenAI SDK client soOpenAIRealtimeWShits 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.