Resume a Speech to Speech session
Resume a Speech to Speech session
Opt in with session.resumption.enabled: true, save conversation.created.conversation.id, then reconnect with ?conversation_id= so prior turns replay before your next utterance.
Opt in and save the id
import json, os, websockets
MODEL = "grok-voice-latest"
async def connect(resume_id=None):
url = f"wss://api.x.ai/v1/realtime?model={MODEL}"
if resume_id:
url += f"&conversation_id={resume_id}"
async with websockets.connect(
url,
additional_headers={"Authorization": f"Bearer {os.environ['XAI_API_KEY']}"},
) as ws:
await ws.send(json.dumps({
"type": "session.update",
"session": {"resumption": {"enabled": True}},
}))
async for raw in ws:
event = json.loads(raw)
if event["type"] == "conversation.created":
saved_id = event["conversation"]["id"]
# persist saved_id for the next reconnect
# ... handle turns
Without the opt-in, closing the WebSocket drops conversation history.
Reconnect
- Reopen
wss://api.x.ai/v1/realtime?model=…&conversation_id={saved}. - Send
session.updatewithresumption.enabled: trueagain — resume must opt in both ways or nothing replays. - Cached turns arrive as
conversation.item.createdbefore your first new turn.
What is replayed
Persisted and replayed on resume:
- User and assistant transcripts
- Assistant tool calls
- Your
function_call_outputresults
History expires after 30 minutes of inactivity.
Pitfalls
- Forgetting
resumption.enabled: trueon the second connect skips replay even with a validconversation_id. - Do not assume audio bytes are cached — plan for transcript/tool context only.
- SIP paths can also pass a saved id; see the SIP how-to for
call_id+conversation_idtogether. - Console API credits are separate from SuperGrok's weekly pool on grok.com.